pwood-wowr 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +41 -0
- data/VERSION.yml +4 -0
- data/lib/wowr.rb +1253 -0
- data/lib/wowr/achievements.rb +143 -0
- data/lib/wowr/arena_team.rb +80 -0
- data/lib/wowr/calendar.rb +78 -0
- data/lib/wowr/character.rb +832 -0
- data/lib/wowr/dungeon.rb +85 -0
- data/lib/wowr/exceptions.rb +163 -0
- data/lib/wowr/extensions.rb +67 -0
- data/lib/wowr/general.rb +39 -0
- data/lib/wowr/guild.rb +85 -0
- data/lib/wowr/guild_bank.rb +188 -0
- data/lib/wowr/item.rb +577 -0
- data/test/wowr_arena_team_test.rb +41 -0
- data/test/wowr_character_test.rb +88 -0
- data/test/wowr_dungeon_test.rb +63 -0
- data/test/wowr_guild_test.rb +27 -0
- data/test/wowr_item_test.rb +8 -0
- data/test/wowr_test.rb +456 -0
- data/test/xml/arena_team_search.xml +60 -0
- data/test/xml/arena_team_single.xml +25 -0
- data/test/xml/armory-search.xml +207 -0
- data/test/xml/armory_search.xml +126 -0
- data/test/xml/benedictt.xml +152 -0
- data/test/xml/character-reputation.xml +82 -0
- data/test/xml/character-sheet.xml +145 -0
- data/test/xml/character-skills.xml +60 -0
- data/test/xml/character-talents.xml +29 -0
- data/test/xml/character_info.xml +141 -0
- data/test/xml/character_search.xml +102 -0
- data/test/xml/dungeonStrings.xml +550 -0
- data/test/xml/dungeons.xml +1658 -0
- data/test/xml/example.xml +127 -0
- data/test/xml/guild-info.xml +302 -0
- data/test/xml/item-info.xml +20 -0
- data/test/xml/item-tooltip.xml +167 -0
- data/test/xml/itemSearch.xml +46 -0
- data/test/xml/item_search.xml +63 -0
- metadata +96 -0
data/README
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Wowr
|
2
|
+
----
|
3
|
+
Ruby Library for the World of Warcraft Armory
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
Introduction
|
8
|
+
------------
|
9
|
+
Wowr is an API for accessing data in the World of Warcraft Armory. Using the XML data provided by the armory, it allows developers to query World of Warcraft items, characters, guilds and arena teams. It is designed to support developers that wish to add WoW information to their Ruby-powered site, as well as larger guild or portal sites for many users.
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
Usage
|
14
|
+
-----
|
15
|
+
See example.rb
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
Documentation
|
20
|
+
-------------
|
21
|
+
Please view the RubyDoc for more information on usage. http://wowr.rubyforge.org/doc/
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Installation
|
26
|
+
------------
|
27
|
+
Wowr can be installed through RubyGems using the command below:
|
28
|
+
gem install wowr
|
29
|
+
|
30
|
+
Alternatively, the latest version can be downloaded from SVN with:
|
31
|
+
svn checkout http://wowr.rubyforge.org/svn/trunk/lib/
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
Author
|
36
|
+
------
|
37
|
+
Originally written by Ben Humphreys benhumphreys[at]gmail.com
|
38
|
+
Maintained by Peter Wood peter+wowr[at]alastria.net
|
39
|
+
Patches from Renaud Chaput and Michael Chen
|
40
|
+
|
41
|
+
Apologies to anyone missed, please let Peter Wood know if this is the case.
|
data/VERSION.yml
ADDED
data/lib/wowr.rb
ADDED
@@ -0,0 +1,1253 @@
|
|
1
|
+
#
|
2
|
+
# Wowr - Ruby library for the World of Warcraft Armory
|
3
|
+
# http://wowr.rubyforge.org/
|
4
|
+
# Written by Ben Humphreys
|
5
|
+
# http://benhumphreys.co.uk/
|
6
|
+
# Matained By Peter Wood
|
7
|
+
# http://narwar.net/
|
8
|
+
#
|
9
|
+
# Author:: Ben Humphreys
|
10
|
+
# Author:: Peter Wood
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'hpricot' # version 0.6
|
14
|
+
rescue LoadError
|
15
|
+
require 'rubygems'
|
16
|
+
require 'hpricot'
|
17
|
+
end
|
18
|
+
require 'net/http'
|
19
|
+
require 'net/https'
|
20
|
+
require 'cgi'
|
21
|
+
require 'fileutils'
|
22
|
+
require 'json'
|
23
|
+
|
24
|
+
|
25
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
26
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
27
|
+
|
28
|
+
require 'wowr/exceptions.rb'
|
29
|
+
require 'wowr/extensions.rb'
|
30
|
+
|
31
|
+
require 'wowr/calendar.rb'
|
32
|
+
require 'wowr/character.rb'
|
33
|
+
require 'wowr/achievements.rb'
|
34
|
+
require 'wowr/guild.rb'
|
35
|
+
require 'wowr/item.rb'
|
36
|
+
require 'wowr/arena_team.rb'
|
37
|
+
require 'wowr/dungeon.rb'
|
38
|
+
require 'wowr/guild_bank.rb'
|
39
|
+
|
40
|
+
module Wowr
|
41
|
+
class API
|
42
|
+
VERSION = '0.4.1'
|
43
|
+
|
44
|
+
@@armory_base_url = 'wowarmory.com/'
|
45
|
+
@@login_base_url = 'battle.net/'
|
46
|
+
|
47
|
+
@@persistant_cookie = 'COM-warcraft'
|
48
|
+
@@temporary_cookie = 'JSESSIONID'
|
49
|
+
|
50
|
+
@@search_url = 'search.xml'
|
51
|
+
|
52
|
+
@@character_sheet_url = 'character-sheet.xml'
|
53
|
+
@@character_talents_url = 'character-talents.xml'
|
54
|
+
@@character_reputation_url = 'character-reputation.xml'
|
55
|
+
|
56
|
+
@@character_achievements_url = 'character-achievements.xml'
|
57
|
+
|
58
|
+
@@calendar_user_url = 'vault/calendar/month-user.json'
|
59
|
+
@@calendar_world_url = 'vault/calendar/month-world.json'
|
60
|
+
@@calendar_detail_url = 'vault/calendar/detail.json'
|
61
|
+
|
62
|
+
@@guild_info_url = 'guild-info.xml'
|
63
|
+
|
64
|
+
@@item_info_url = 'item-info.xml'
|
65
|
+
@@item_tooltip_url = 'item-tooltip.xml'
|
66
|
+
|
67
|
+
@@arena_team_url = 'team-info.xml'
|
68
|
+
|
69
|
+
@@guild_bank_contents_url = 'vault/guild-bank-contents.xml'
|
70
|
+
@@guild_bank_log_url = 'vault/guild-bank-log.xml'
|
71
|
+
|
72
|
+
@@login_url = 'login/login.xml'
|
73
|
+
|
74
|
+
@@dungeons_url = 'data/dungeons.xml'
|
75
|
+
@@dungeons_strings_url = 'data/dungeonStrings.xml'
|
76
|
+
|
77
|
+
@@max_connection_tries = 10
|
78
|
+
|
79
|
+
@@cache_directory_path = 'cache/'
|
80
|
+
|
81
|
+
@@user_agent = 'Mozilla/5.0 Gecko/20070219 Firefox/2.0.0.2'
|
82
|
+
|
83
|
+
@@default_cache_timeout = (7*24*60*60)
|
84
|
+
@@failed_cache_timeout = (60*60*24)
|
85
|
+
@@cache_failed_requests = true # cache requests that resulted in an error from the armory
|
86
|
+
|
87
|
+
cattr_accessor :armory_base_url, :search_url,
|
88
|
+
:character_sheet_url, :character_talents_url, :character_reputation_url,
|
89
|
+
:guild_info_url,
|
90
|
+
:item_info_url, :item_tooltip_url,
|
91
|
+
:arena_team_url,
|
92
|
+
:guild_bank_contents_url, :guild_bank_log_url,
|
93
|
+
:login_url,
|
94
|
+
:dungeons_url, :dungeons_strings_url,
|
95
|
+
:max_connection_tries,
|
96
|
+
:cache_directory_path,
|
97
|
+
:default_cache_timeout, :failed_cache_timeout, :cache_failed_requests,
|
98
|
+
:calendar_user_url, :calendar_world_url, :calendar_detail_url, :persistant_cookie, :temporary_cookie
|
99
|
+
|
100
|
+
@@search_types = {
|
101
|
+
:item => 'items',
|
102
|
+
:character => 'characters',
|
103
|
+
:guild => 'guilds',
|
104
|
+
:arena_team => 'arenateams'
|
105
|
+
}
|
106
|
+
|
107
|
+
@@arena_team_sizes = [2, 3, 5]
|
108
|
+
|
109
|
+
@@calendar_world_types = ['player', 'holiday', 'bg', 'darkmoon', 'raidLockout', 'raidReset', 'holidayWeekly']
|
110
|
+
@@calendar_user_types = ['raid', 'dungeon', 'pvp', 'meeting', 'other']
|
111
|
+
|
112
|
+
attr_accessor :character_name, :guild_name, :realm, :locale, :lang, :caching, :cache_timeout, :debug
|
113
|
+
|
114
|
+
|
115
|
+
# Constructor
|
116
|
+
# Accepts an optional hash of parameters to create defaults for all API requests
|
117
|
+
# * options (Hash) - Hash used to set default values for all API requests
|
118
|
+
def initialize(options = {})
|
119
|
+
@character_name = options[:character_name]
|
120
|
+
@guild_name = options[:guild_name]
|
121
|
+
@realm = options[:realm]
|
122
|
+
@locale = options[:locale] || 'us'
|
123
|
+
@lang = options[:lang].nil? ? 'default' : options[:lang]
|
124
|
+
@caching = options[:caching].nil? ? true : options[:caching]
|
125
|
+
@cache_timeout = options[:cache_timeout] || @@default_cache_timeout
|
126
|
+
@debug = options[:debug] || false
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# General-purpose search
|
131
|
+
# All specific searches are wrappers around this method. Best to use those instead.
|
132
|
+
# Returns an array of results of the type requested (Wowr::Classes::SearchCharacter etc.) or an empty array.
|
133
|
+
# Searches across all realms.
|
134
|
+
# Caching is disabled for searching.
|
135
|
+
# * string (String) Search string
|
136
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
137
|
+
def search(string, options = {})
|
138
|
+
if (string.is_a?(Hash))
|
139
|
+
options = string
|
140
|
+
else
|
141
|
+
options.merge!(:search => string)
|
142
|
+
end
|
143
|
+
|
144
|
+
options = merge_defaults(options)
|
145
|
+
|
146
|
+
if options[:search].nil? || options[:search].empty?
|
147
|
+
raise Wowr::Exceptions::NoSearchString.new
|
148
|
+
end
|
149
|
+
|
150
|
+
if !@@search_types.has_value?(options[:type])
|
151
|
+
raise Wowr::Exceptions::InvalidSearchType.new(options[:type])
|
152
|
+
end
|
153
|
+
|
154
|
+
options.merge!(:caching => false)
|
155
|
+
options.delete(:realm) # all searches are across realms
|
156
|
+
|
157
|
+
xml = get_xml(@@search_url, options)
|
158
|
+
|
159
|
+
results = []
|
160
|
+
|
161
|
+
if (xml) && (xml%'armorySearch') && (xml%'armorySearch'%'searchResults')
|
162
|
+
case options[:type]
|
163
|
+
|
164
|
+
when @@search_types[:item]
|
165
|
+
(xml%'armorySearch'%'searchResults'%'items'/:item).each do |item|
|
166
|
+
results << Wowr::Classes::SearchItem.new(item)
|
167
|
+
end
|
168
|
+
|
169
|
+
when @@search_types[:character]
|
170
|
+
(xml%'armorySearch'%'searchResults'%'characters'/:character).each do |char|
|
171
|
+
results << Wowr::Classes::SearchCharacter.new(char, self)
|
172
|
+
end
|
173
|
+
|
174
|
+
when @@search_types[:guild]
|
175
|
+
(xml%'armorySearch'%'searchResults'%'guilds'/:guild).each do |guild|
|
176
|
+
results << Wowr::Classes::SearchGuild.new(guild)
|
177
|
+
end
|
178
|
+
|
179
|
+
when @@search_types[:arena_team]
|
180
|
+
(xml%'armorySearch'%'searchResults'%'arenaTeams'/:arenaTeam).each do |team|
|
181
|
+
results << Wowr::Classes::SearchArenaTeam.new(team)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
return results
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
# Characters
|
191
|
+
# Returns an array of results of Wowr::Classes::SearchCharacter or an empty array.
|
192
|
+
# Searches across all realms.
|
193
|
+
# Caching is disabled for searching.
|
194
|
+
# Parameters
|
195
|
+
# * name (String) Name of the character to search for
|
196
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
197
|
+
def search_characters(name, options = {})
|
198
|
+
if (name.is_a?(Hash))
|
199
|
+
options = name
|
200
|
+
else
|
201
|
+
options.merge!(:search => name)
|
202
|
+
end
|
203
|
+
|
204
|
+
options.merge!(:type => @@search_types[:character])
|
205
|
+
return search(options)
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
# Get the full details of a character.
|
210
|
+
# Requires realm.
|
211
|
+
# * name (String) Name of the character to get, defaults to that specified in constructor
|
212
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
213
|
+
def get_character(name = @character_name, options = {})
|
214
|
+
options = character_options(name, options)
|
215
|
+
character_sheet = get_xml(@@character_sheet_url, options)
|
216
|
+
character_reputation = get_xml(@@character_reputation_url, options)
|
217
|
+
|
218
|
+
# FIXME
|
219
|
+
if true
|
220
|
+
return Wowr::Classes::FullCharacter.new(character_sheet,
|
221
|
+
character_reputation,
|
222
|
+
self)
|
223
|
+
else
|
224
|
+
raise Wowr::Excceptions::CharacterNotFound.new(options[:character_name])
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
# DEPRECATED
|
230
|
+
# See get_character
|
231
|
+
def get_character_sheet(name = @character_name, options = {})
|
232
|
+
return get_character(name, options)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Get achievement infos for a character.
|
236
|
+
# Requires realm.
|
237
|
+
# * name (String) Name of the character to get, defaults to that specified in constructor
|
238
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
239
|
+
def get_character_achievements(name = @character_name, options = {})
|
240
|
+
options = character_options(name, options)
|
241
|
+
|
242
|
+
character_achievements = get_xml(@@character_achievements_url, options)
|
243
|
+
|
244
|
+
return Wowr::Classes::CharacterAchievementsInfo.new(character_achievements, self)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Get details for all achievements in a category for a character.
|
248
|
+
# Requires realm.
|
249
|
+
# * achievement_category (Integer) ID of the achievement category
|
250
|
+
# * name (String) Name of the character to get, defaults to that specified in constructor
|
251
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
252
|
+
def get_character_achievements_category(achievement_category, name = @character_name, options = {})
|
253
|
+
options = character_options(name, options)
|
254
|
+
options[:achievement_category] = achievement_category.to_i
|
255
|
+
|
256
|
+
character_achievements_category = get_xml(@@character_achievements_url, options)
|
257
|
+
|
258
|
+
return Wowr::Classes::AchievementsList.new(character_achievements_category, self)
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
# Find all guilds with the given string, return array of Wowr::Classes::SearchGuild.
|
263
|
+
# Searches across all realms.
|
264
|
+
# Caching is disabled for searching.
|
265
|
+
# * name (String) Name of the guild to search for
|
266
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
267
|
+
def search_guilds(name, options = {})
|
268
|
+
if (name.is_a?(Hash))
|
269
|
+
options = name
|
270
|
+
else
|
271
|
+
options.merge!(:search => name)
|
272
|
+
end
|
273
|
+
options.delete(:realm)
|
274
|
+
|
275
|
+
options.merge!(:type => @@search_types[:guild])
|
276
|
+
return search(options)
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
# Get the guild details.
|
281
|
+
# Guild name is optional, assuming it's set in the api constructor.
|
282
|
+
# Requires realm.
|
283
|
+
# * name (String) Name of the guild to retrieve, defaults to that specified in constructor
|
284
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
285
|
+
def get_guild(name = @guild_name, options = {})
|
286
|
+
if (name.is_a?(Hash))
|
287
|
+
options = name
|
288
|
+
else
|
289
|
+
options.merge!(:guild_name => name)
|
290
|
+
end
|
291
|
+
|
292
|
+
options = merge_defaults(options)
|
293
|
+
|
294
|
+
if options[:guild_name].nil? || options[:guild_name] == ""
|
295
|
+
raise Wowr::Exceptions::GuildNameNotSet.new
|
296
|
+
elsif options[:realm].nil? || options[:realm].empty?
|
297
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
298
|
+
end
|
299
|
+
|
300
|
+
xml = get_xml(@@guild_info_url, options)
|
301
|
+
|
302
|
+
if !(xml%'guildInfo').children.empty?
|
303
|
+
return Wowr::Classes::FullGuild.new(xml)
|
304
|
+
else
|
305
|
+
raise Wowr::Exceptions::GuildNotFound.new(options[:guild_name])
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
# Search for items with the specified name.
|
311
|
+
# Returns an array of Wowr::Classes::SearchItem.
|
312
|
+
# Searches across all realms.
|
313
|
+
# Caching is disabled for searching.
|
314
|
+
# * name (String) Name of the item
|
315
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
316
|
+
def search_items(name, options = {})
|
317
|
+
if (name.is_a?(Hash))
|
318
|
+
options = name
|
319
|
+
else
|
320
|
+
options.merge!(:search => name)
|
321
|
+
end
|
322
|
+
|
323
|
+
options.merge!(:type => @@search_types[:item])
|
324
|
+
return search(options)
|
325
|
+
end
|
326
|
+
|
327
|
+
|
328
|
+
# Get the full item details (Wowr::Classes::FullItem) with the given id.
|
329
|
+
# Composite of Wowr::Classes::ItemInfo and Wowr::Classes::ItemTooltip data.
|
330
|
+
# Item requests are identical across realms.
|
331
|
+
# * id (Fixnum) ID of the item
|
332
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
333
|
+
def get_item(id, options = {})
|
334
|
+
if (id.is_a?(Hash))
|
335
|
+
options = id
|
336
|
+
else
|
337
|
+
options.merge!(:item_id => id)
|
338
|
+
end
|
339
|
+
|
340
|
+
options = merge_defaults(options)
|
341
|
+
options.delete(:realm)
|
342
|
+
|
343
|
+
info = get_xml(@@item_info_url, options)
|
344
|
+
tooltip = get_xml(@@item_tooltip_url, options)
|
345
|
+
|
346
|
+
if (info%'itemInfo'%'item') && !tooltip.nil?
|
347
|
+
return Wowr::Classes::FullItem.new(info%'itemInfo'%'item', tooltip%'itemTooltip', self)
|
348
|
+
else
|
349
|
+
raise Wowr::Exceptions::ItemNotFound.new(options[:item_id])
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
# Get the basic item information Wowr::Classes::ItemInfo.
|
355
|
+
# Item requests are identical across realms.
|
356
|
+
# * id (Fixnum) ID of the item
|
357
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
358
|
+
def get_item_info(id, options = {})
|
359
|
+
if (id.is_a?(Hash))
|
360
|
+
options = id
|
361
|
+
else
|
362
|
+
options.merge!(:item_id => id)
|
363
|
+
end
|
364
|
+
|
365
|
+
options = merge_defaults(options)
|
366
|
+
options.delete(:realm)
|
367
|
+
|
368
|
+
xml = get_xml(@@item_info_url, options)
|
369
|
+
|
370
|
+
if (xml%'itemInfo'%'item')
|
371
|
+
return Wowr::Classes::ItemInfo.new(xml%'itemInfo'%'item', self)
|
372
|
+
else
|
373
|
+
raise Wowr::Exceptions::ItemNotFound.new(options[:item_id])
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
# Get full item details including stats Wowr::Classes::ItemTooltip.
|
379
|
+
# Item requests are identical across realms.
|
380
|
+
# * id (Fixnum) ID of the item
|
381
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
382
|
+
def get_item_tooltip(id, options = {})
|
383
|
+
if (id.is_a?(Hash))
|
384
|
+
options = id
|
385
|
+
else
|
386
|
+
options.merge!(:item_id => id)
|
387
|
+
end
|
388
|
+
|
389
|
+
options = merge_defaults(options)
|
390
|
+
options.delete(:realm)
|
391
|
+
|
392
|
+
xml = get_xml(@@item_tooltip_url, options)
|
393
|
+
|
394
|
+
if !xml.nil?
|
395
|
+
return Wowr::Classes::ItemTooltip.new(xml%'itemTooltip')
|
396
|
+
else
|
397
|
+
raise Wowr::Exceptions::ItemNotFound.new(options[:item_id])
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
|
402
|
+
# Search for arena teams with the given name of any size.
|
403
|
+
# Returns an array of Wowr::Classes::SearchArenaTeam
|
404
|
+
# Searches across all realms.
|
405
|
+
# Caching is disabled for searching.
|
406
|
+
# * name (String) Name of the arena team to seach for
|
407
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
408
|
+
def search_arena_teams(name, options = {})
|
409
|
+
if (name.is_a?(Hash))
|
410
|
+
options = name
|
411
|
+
else
|
412
|
+
options.merge!(:search => name)
|
413
|
+
end
|
414
|
+
|
415
|
+
options.merge!(:type => @@search_types[:arena_team])
|
416
|
+
return search(options)
|
417
|
+
end
|
418
|
+
|
419
|
+
|
420
|
+
# Get the arena team of the given name and size, on the specified realm.
|
421
|
+
# Returns Wowr::Classes::FullArenaTeam
|
422
|
+
# Requires realm.
|
423
|
+
# * name (String) Team arena name
|
424
|
+
# * size (Fixnum) Must be 2, 3 or 5
|
425
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
426
|
+
def get_arena_team(name, size = nil, options = {})
|
427
|
+
if name.is_a?(Hash)
|
428
|
+
options = name
|
429
|
+
elsif size.is_a?(Hash)
|
430
|
+
options = size
|
431
|
+
options.merge!(:team_name => name)
|
432
|
+
else
|
433
|
+
options.merge!(:team_name => name, :team_size => size)
|
434
|
+
end
|
435
|
+
|
436
|
+
options = merge_defaults(options)
|
437
|
+
|
438
|
+
if options[:team_name].nil? || options[:team_name].empty?
|
439
|
+
raise Wowr::Exceptions::ArenaTeamNameNotSet.new
|
440
|
+
end
|
441
|
+
|
442
|
+
if options[:realm].nil? || options[:realm].empty?
|
443
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
444
|
+
end
|
445
|
+
|
446
|
+
if !@@arena_team_sizes.include?(options[:team_size])
|
447
|
+
raise Wowr::Exceptions::InvalidArenaTeamSize.new("Arena teams size must be: #{@@arena_team_sizes.inspect}")
|
448
|
+
end
|
449
|
+
|
450
|
+
xml = get_xml(@@arena_team_url, options)
|
451
|
+
|
452
|
+
if !(xml%'arenaTeam').children.empty?
|
453
|
+
return Wowr::Classes::ArenaTeam.new(xml%'arenaTeam')
|
454
|
+
else
|
455
|
+
raise Wowr::Exceptions::ArenaTeamNotFound.new(options[:team_name])
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
|
460
|
+
# Get the current items within the guild bank.
|
461
|
+
# Note that the bags and items the user can see is dependent on their privileges.
|
462
|
+
# Requires realm.
|
463
|
+
# * cookie (String) Cookie data returned by the login function.
|
464
|
+
# * guild_name (String) Guild name
|
465
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
466
|
+
def get_guild_bank_contents(cookie, guild_name = @guild_name, options = {})
|
467
|
+
if (cookie.is_a?(Hash))
|
468
|
+
options = cookie
|
469
|
+
elsif (guild_name.is_a?(Hash))
|
470
|
+
options = guild_name
|
471
|
+
options.merge!(:cookie => cookie)
|
472
|
+
options.merge!(:guild_name => @guild_name)
|
473
|
+
else
|
474
|
+
options.merge!(:cookie => cookie)
|
475
|
+
options.merge!(:guild_name => guild_name)
|
476
|
+
end
|
477
|
+
options = merge_defaults(options)
|
478
|
+
|
479
|
+
if options[:cookie].nil? || options[:cookie] == ""
|
480
|
+
raise Wowr::Exceptions::CookieNotSet.new
|
481
|
+
elsif options[:guild_name].nil? || options[:guild_name] == ""
|
482
|
+
raise Wowr::Exceptions::GuildNameNotSet.new
|
483
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
484
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
485
|
+
end
|
486
|
+
|
487
|
+
options.merge!(:secure => true)
|
488
|
+
|
489
|
+
xml = get_xml(@@guild_bank_contents_url, options)
|
490
|
+
|
491
|
+
if !(xml%'guildBank').children.empty?
|
492
|
+
return Wowr::Classes::GuildBankContents.new(xml, self)
|
493
|
+
else
|
494
|
+
raise Wowr::Exceptions::GuildBankNotFound.new(options[:guild_name])
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
|
499
|
+
# Get a particular page of the guild bank transaction log.
|
500
|
+
# Each page contains up to 1000 transactions, other pages can be specified using :group in the options hash.
|
501
|
+
# Note that data returned is specific to the logged in user's privileges.
|
502
|
+
# Requires realm.
|
503
|
+
# * cookie (String) Cookie data returned by the login function
|
504
|
+
# * guild_name (String) Guild name
|
505
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
506
|
+
def get_guild_bank_log(cookie, name = @guild_name, options = {})
|
507
|
+
if (cookie.is_a?(Hash))
|
508
|
+
options = cookie
|
509
|
+
elsif (name.is_a?(Hash))
|
510
|
+
options = name
|
511
|
+
options.merge!(:cookie => cookie)
|
512
|
+
options.merge!(:guild_name => @guild_name)
|
513
|
+
else
|
514
|
+
options.merge!(:cookie => cookie)
|
515
|
+
options.merge!(:guild_name => name)
|
516
|
+
end
|
517
|
+
|
518
|
+
options = merge_defaults(options)
|
519
|
+
|
520
|
+
if options[:cookie].nil? || options[:cookie] == ""
|
521
|
+
raise Wowr::Exceptions::CookieNotSet.new
|
522
|
+
elsif options[:guild_name].nil? || options[:guild_name] == ""
|
523
|
+
raise Wowr::Exceptions::GuildNameNotSet.new
|
524
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
525
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
526
|
+
end
|
527
|
+
|
528
|
+
options.merge!(:secure => true)
|
529
|
+
|
530
|
+
xml = get_xml(@@guild_bank_log_url, options)
|
531
|
+
|
532
|
+
if !(xml%'guildBank').children.empty?
|
533
|
+
return Wowr::Classes::GuildBankLog.new(xml, self)
|
534
|
+
else
|
535
|
+
raise Wowr::Exceptions::GuildBankNotFound.new(options[:guild_name])
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
|
540
|
+
def get_complete_world_calendar(cookie, name = @character_name, realm = @realm, options = {})
|
541
|
+
if (cookie.is_a?(Hash))
|
542
|
+
options = cookie
|
543
|
+
elsif (name.is_a?(Hash))
|
544
|
+
options = name
|
545
|
+
options.merge!(:cookie => cookie)
|
546
|
+
options.merge!(:character_name => @character_name)
|
547
|
+
options.merge!(:realm => @realm)
|
548
|
+
elsif (realm.is_a?(Hash))
|
549
|
+
options = realm
|
550
|
+
options.merge!(:cookie => cookie)
|
551
|
+
options.merge!(:character_name => name)
|
552
|
+
options.merge!(:realm => @realm)
|
553
|
+
else
|
554
|
+
options.merge!(:cookie => cookie)
|
555
|
+
options.merge!(:character_name => name)
|
556
|
+
options.merge!(:realm => realm)
|
557
|
+
end
|
558
|
+
|
559
|
+
options = merge_defaults(options)
|
560
|
+
|
561
|
+
events = []
|
562
|
+
|
563
|
+
@@calendar_world_types.each do |type|
|
564
|
+
options.merge!(:calendar_type => type)
|
565
|
+
events = events.concat(get_world_calendar(options))
|
566
|
+
end
|
567
|
+
|
568
|
+
events.sort! { |a,b| a.start <=> b.start }
|
569
|
+
|
570
|
+
return events
|
571
|
+
end
|
572
|
+
|
573
|
+
|
574
|
+
def get_world_calendar(cookie, name = @character_name, realm = @realm, options = {})
|
575
|
+
if (cookie.is_a?(Hash))
|
576
|
+
options = cookie
|
577
|
+
elsif (name.is_a?(Hash))
|
578
|
+
options = name
|
579
|
+
options.merge!(:cookie => cookie)
|
580
|
+
options.merge!(:character_name => @character_name)
|
581
|
+
options.merge!(:realm => @realm)
|
582
|
+
elsif (realm.is_a?(Hash))
|
583
|
+
options = realm
|
584
|
+
options.merge!(:cookie => cookie)
|
585
|
+
options.merge!(:character_name => name)
|
586
|
+
options.merge!(:realm => @realm)
|
587
|
+
else
|
588
|
+
options.merge!(:cookie => cookie)
|
589
|
+
options.merge!(:character_name => name)
|
590
|
+
options.merge!(:realm => realm)
|
591
|
+
end
|
592
|
+
|
593
|
+
options = merge_defaults(options)
|
594
|
+
|
595
|
+
if options[:cookie].nil? || options[:cookie] == ""
|
596
|
+
raise Wowr::Exceptions::CookieNotSet.new
|
597
|
+
elsif options[:character_name].nil? || options[:guild_name] == ""
|
598
|
+
raise Wowr::Exceptions::CharacterNameNotSet.new
|
599
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
600
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
601
|
+
end
|
602
|
+
|
603
|
+
options.merge!(:secure => true)
|
604
|
+
|
605
|
+
json = get_json(@@calendar_world_url, options)
|
606
|
+
|
607
|
+
if (!json["events"])
|
608
|
+
raise Wowr::Exceptions::EmptyPage
|
609
|
+
end
|
610
|
+
|
611
|
+
events = []
|
612
|
+
|
613
|
+
json["events"].each do |event|
|
614
|
+
events << Wowr::Classes::WorldCalendar.new(event, nil)
|
615
|
+
end
|
616
|
+
|
617
|
+
return events
|
618
|
+
end
|
619
|
+
|
620
|
+
|
621
|
+
def get_full_user_calendar(cookie, name = @character_name, realm = @realm, options = {})
|
622
|
+
if (cookie.is_a?(Hash))
|
623
|
+
options = cookie
|
624
|
+
elsif (name.is_a?(Hash))
|
625
|
+
options = name
|
626
|
+
options.merge!(:cookie => cookie)
|
627
|
+
options.merge!(:character_name => @character_name)
|
628
|
+
options.merge!(:realm => @realm)
|
629
|
+
elsif (realm.is_a?(Hash))
|
630
|
+
options = realm
|
631
|
+
options.merge!(:cookie => cookie)
|
632
|
+
options.merge!(:character_name => name)
|
633
|
+
options.merge!(:realm => @realm)
|
634
|
+
else
|
635
|
+
options.merge!(:cookie => cookie)
|
636
|
+
options.merge!(:character_name => name)
|
637
|
+
options.merge!(:realm => realm)
|
638
|
+
end
|
639
|
+
|
640
|
+
options = merge_defaults(options)
|
641
|
+
|
642
|
+
skel_events = get_user_calendar(options)
|
643
|
+
full_events = []
|
644
|
+
|
645
|
+
skel_events.each do |se|
|
646
|
+
options.merge!(:event => se.id)
|
647
|
+
full_events << get_calendar_event(options)
|
648
|
+
end
|
649
|
+
|
650
|
+
full_events.sort! { |a,b| a.start <=> b.start }
|
651
|
+
|
652
|
+
return full_events
|
653
|
+
end
|
654
|
+
|
655
|
+
|
656
|
+
def get_user_calendar(cookie, name = @character_name, realm = @realm, options = {})
|
657
|
+
if (cookie.is_a?(Hash))
|
658
|
+
options = cookie
|
659
|
+
elsif (name.is_a?(Hash))
|
660
|
+
options = name
|
661
|
+
options.merge!(:cookie => cookie)
|
662
|
+
options.merge!(:character_name => @character_name)
|
663
|
+
options.merge!(:realm => @realm)
|
664
|
+
elsif (realm.is_a?(Hash))
|
665
|
+
options = realm
|
666
|
+
options.merge!(:cookie => cookie)
|
667
|
+
options.merge!(:character_name => name)
|
668
|
+
options.merge!(:realm => @realm)
|
669
|
+
else
|
670
|
+
options.merge!(:cookie => cookie)
|
671
|
+
options.merge!(:character_name => name)
|
672
|
+
options.merge!(:realm => realm)
|
673
|
+
end
|
674
|
+
|
675
|
+
options = merge_defaults(options)
|
676
|
+
|
677
|
+
if options[:cookie].nil? || options[:cookie] == ""
|
678
|
+
raise Wowr::Exceptions::CookieNotSet.new
|
679
|
+
elsif options[:character_name].nil? || options[:guild_name] == ""
|
680
|
+
raise Wowr::Exceptions::CharacterNameNotSet.new
|
681
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
682
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
683
|
+
end
|
684
|
+
|
685
|
+
options.merge!(:secure => true)
|
686
|
+
|
687
|
+
json = get_json(@@calendar_user_url, options)
|
688
|
+
|
689
|
+
if (!json["events"])
|
690
|
+
raise Wowr::Exceptions::EmptyPage
|
691
|
+
end
|
692
|
+
|
693
|
+
events = []
|
694
|
+
|
695
|
+
json["events"].each do |event|
|
696
|
+
events << Wowr::Classes::UserCalendar.new(event, nil)
|
697
|
+
end
|
698
|
+
|
699
|
+
return events
|
700
|
+
end
|
701
|
+
|
702
|
+
|
703
|
+
def get_calendar_event (cookie, event = nil, name = @character_name, realm = @realm, options = {})
|
704
|
+
if (cookie.is_a?(Hash))
|
705
|
+
options = cookie
|
706
|
+
elsif (event.is_a?(Hash))
|
707
|
+
options = event
|
708
|
+
options.merge!(:cookie => cookie)
|
709
|
+
options.merge!(:event => nil)
|
710
|
+
options.merge!(:character_name => @character_name)
|
711
|
+
options.merge!(:realm => @realm)
|
712
|
+
elsif (name.is_a?(Hash))
|
713
|
+
options = name
|
714
|
+
options.merge!(:cookie => cookie)
|
715
|
+
options.merge!(:event => event)
|
716
|
+
options.merge!(:character_name => @character_name)
|
717
|
+
options.merge!(:realm => @realm)
|
718
|
+
elsif (realm.is_a?(Hash))
|
719
|
+
options = realm
|
720
|
+
options.merge!(:cookie => cookie)
|
721
|
+
options.merge!(:event => event)
|
722
|
+
options.merge!(:character_name => name)
|
723
|
+
options.merge!(:realm => @realm)
|
724
|
+
else
|
725
|
+
options.merge!(:cookie => cookie)
|
726
|
+
options.merge!(:event => event)
|
727
|
+
options.merge!(:character_name => name)
|
728
|
+
options.merge!(:realm => realm)
|
729
|
+
end
|
730
|
+
|
731
|
+
options = merge_defaults(options)
|
732
|
+
|
733
|
+
if options[:cookie].nil? || options[:cookie] == ""
|
734
|
+
raise Wowr::Exceptions::CookieNotSet.new
|
735
|
+
elsif options[:character_name].nil? || options[:guild_name] == ""
|
736
|
+
raise Wowr::Exceptions::CharacterNameNotSet.new
|
737
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
738
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
739
|
+
elsif options[:event].nil? || options[:event] == ""
|
740
|
+
raise Wowr::Exceptions::EventNotSet.new
|
741
|
+
end
|
742
|
+
|
743
|
+
options.merge!(:secure => true)
|
744
|
+
|
745
|
+
json = get_json(@@calendar_detail_url, options)
|
746
|
+
|
747
|
+
if (!json.is_a?(Hash))
|
748
|
+
raise Wowr::Exceptions::EmptyPage
|
749
|
+
end
|
750
|
+
|
751
|
+
return Wowr::Classes::UserDetailCalendar.new(json, nil)
|
752
|
+
end
|
753
|
+
|
754
|
+
|
755
|
+
# Get complete list of dungeons.
|
756
|
+
# WARNING: This gets two 6k xml files so it's not that fast
|
757
|
+
# Takes 0.2s with cache, 2s without
|
758
|
+
# New approach: Instead of passing the XML around and performing multiple
|
759
|
+
# search lookups to find the elements, run through each XML file once
|
760
|
+
# adding data to classes as they appear using hash lookup.
|
761
|
+
# Went from 14s to 2s :)
|
762
|
+
# * options (Hash) Optional hash of arguments identical to those used in the API constructor (realm, debug, cache etc.)
|
763
|
+
def get_dungeons(options = {})
|
764
|
+
options = merge_defaults(options)
|
765
|
+
|
766
|
+
# dungeon_strings contains names for ids
|
767
|
+
dungeon_xml = get_xml(@@dungeons_url, options)%'dungeons'
|
768
|
+
|
769
|
+
dungeon_strings_xml = get_xml(@@dungeons_strings_url, options)
|
770
|
+
|
771
|
+
results = {}
|
772
|
+
|
773
|
+
# TODO: Pass the correct part of dungeon_strings_xml to each dungeon?
|
774
|
+
if dungeon_xml && !dungeon_xml.children.empty?
|
775
|
+
(dungeon_xml/:dungeon).each do |elem|
|
776
|
+
dungeon = Wowr::Classes::Dungeon.new(elem)
|
777
|
+
results[dungeon.id] = dungeon if dungeon.id
|
778
|
+
results[dungeon.key] = dungeon if dungeon.key
|
779
|
+
end
|
780
|
+
|
781
|
+
(dungeon_strings_xml/:dungeon).each do |elem|
|
782
|
+
id = elem[:id].to_i
|
783
|
+
key = elem[:key]
|
784
|
+
|
785
|
+
if (results[id])
|
786
|
+
results[id].add_name_data(elem)
|
787
|
+
elsif (results[key])
|
788
|
+
results[key].add_name_data(elem)
|
789
|
+
end
|
790
|
+
end
|
791
|
+
else
|
792
|
+
raise Wowr::Exceptions::InvalidXML.new()
|
793
|
+
end
|
794
|
+
|
795
|
+
return results
|
796
|
+
end
|
797
|
+
|
798
|
+
|
799
|
+
# Logs the user into the armory using their main world of warcraft username, password and authenticator if given/required.
|
800
|
+
# Uses SSL to send details to the login page. Both must be set to true in order to recieve the long life cookie as the second value.
|
801
|
+
#
|
802
|
+
# short = api.login("username", "password")
|
803
|
+
# short, long = api.login("username", "password", nil, true)
|
804
|
+
#
|
805
|
+
def login(username, password, authenticator = nil, both = false)
|
806
|
+
# Create the base URL we will be POSTing to.
|
807
|
+
authentication_url = base_url(@locale, {:secure => true, :login => true}) + @@login_url + "?app=armory"
|
808
|
+
|
809
|
+
# Ensure we add the correct bounce point.
|
810
|
+
if (@locale == "www")
|
811
|
+
authentication_url += "&ref=http://www.wowarmory.com/index.xml"
|
812
|
+
else
|
813
|
+
authentication_url += "&ref=http://#{@locale}.wowarmory.com/index.xml"
|
814
|
+
end
|
815
|
+
|
816
|
+
# Ensure we have no final stage.
|
817
|
+
redirectstage = nil
|
818
|
+
|
819
|
+
# Post the first stage
|
820
|
+
stage1 = login_http(authentication_url, true, nil, { 'accountName' => username, 'password' => password }, true)
|
821
|
+
|
822
|
+
# Check what happened.
|
823
|
+
if (stage1.code == "200")
|
824
|
+
# We didn't pass, but we didn't fail yet if we need an authenticator.
|
825
|
+
stage1doc = Hpricot.XML(stage1.body)
|
826
|
+
|
827
|
+
# Check to see if our details were incorrect.
|
828
|
+
if (stage1doc.at("tas:accountName")['error'])
|
829
|
+
# We have had an error returned to us with regards to our username or password.
|
830
|
+
raise Wowr::Exceptions::InvalidLoginDetails
|
831
|
+
end
|
832
|
+
|
833
|
+
# Okey do we require an authenticator?
|
834
|
+
if (!stage1doc.at("tas:authType")['value'] || stage1doc.at("tas:authType")['value'] != "BA")
|
835
|
+
# Ummm, we're not invalid nor do we have no clue about the authType required now.
|
836
|
+
raise Wowr::Exceptions::LoginBroken
|
837
|
+
end
|
838
|
+
|
839
|
+
# Do we have an authenticator code to use?
|
840
|
+
raise Wowr::Exceptions::LoginRequiresAuthenticator if (!authenticator)
|
841
|
+
|
842
|
+
stage1cookie = nil
|
843
|
+
|
844
|
+
# Get the *authentication sites* JSESSIONID.
|
845
|
+
stage1.header['set-cookie'].scan(/JSESSIONID=(.*?);/) {
|
846
|
+
stage1cookie = $1
|
847
|
+
}
|
848
|
+
|
849
|
+
# Let's post the authenticator and the session for this login.
|
850
|
+
stage2 = login_http(authentication_url, true, { 'JSESSIONID' => stage1cookie }, { 'authValue' => authenticator }, true)
|
851
|
+
|
852
|
+
# So now we check what happened.
|
853
|
+
if (stage2.code == "200")
|
854
|
+
# This isn't a good sign, we should have redirected now.
|
855
|
+
stage2doc = Hpricot.XML(stage2.body)
|
856
|
+
|
857
|
+
# Error is obvious
|
858
|
+
if (stage2doc.at("tas:accountName")['error'])
|
859
|
+
# We have had an error returned to us with regards to our username or password.
|
860
|
+
raise Wowr::Exceptions::InvalidLoginDetails
|
861
|
+
end
|
862
|
+
|
863
|
+
# Error isn't obvious, we can't continue.
|
864
|
+
raise Wowr::Exceptions::LoginBroken
|
865
|
+
elsif (stage2.code == "302")
|
866
|
+
redirectstage = stage2
|
867
|
+
end
|
868
|
+
elsif (stage1.code == "302")
|
869
|
+
redirectstage = stage1
|
870
|
+
end
|
871
|
+
|
872
|
+
# We should have been redirected by now.
|
873
|
+
if (!redirectstage)
|
874
|
+
raise Wowr::Exceptions::LoginBroken
|
875
|
+
end
|
876
|
+
|
877
|
+
# Time to obtain our next URL and our long term cookie.
|
878
|
+
long_cookie = nil
|
879
|
+
|
880
|
+
redirectstage.header['set-cookie'].scan(/#{@@persistant_cookie}=(.*?);/) {
|
881
|
+
long_cookie = $1
|
882
|
+
}
|
883
|
+
|
884
|
+
# Let's bounce to our page that will give us our short term cookie, URL has Kerbrose style ticket.
|
885
|
+
short_cookie = login_final_bounce(redirectstage.header['location'])
|
886
|
+
|
887
|
+
# So what does the user want?
|
888
|
+
if (both)
|
889
|
+
return short_cookie, long_cookie
|
890
|
+
else
|
891
|
+
return short_cookie
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
# Reobtains a short term cookie by using the given long life cookie.
|
896
|
+
def refresh_login(long_life_cookie)
|
897
|
+
# Create the base URL we will be POSTing to.
|
898
|
+
authentication_url = base_url(@locale, {:secure => true, :login => true}) + @@login_url + "?app=armory"
|
899
|
+
|
900
|
+
# Ensure we add the correct bounce point.
|
901
|
+
if (@locale == "www")
|
902
|
+
authentication_url += "&ref=http://www.wowarmory.com/index.xml"
|
903
|
+
else
|
904
|
+
authentication_url += "&ref=http://#{@locale}.wowarmory.com/index.xml"
|
905
|
+
end
|
906
|
+
|
907
|
+
# All we need to do is goto the armory login page passing our long life cookie, we should get 302 instantly.
|
908
|
+
stage1 = login_http(authentication_url, true, { @@persistant_cookie => long_life_cookie })
|
909
|
+
|
910
|
+
# Let's see
|
911
|
+
if (stage1.code == "200")
|
912
|
+
# It's no good, our cookie doesn't work anymore.
|
913
|
+
raise Wowr::Exceptions::InvalidLoginDetails
|
914
|
+
elsif (stage1.code == "302")
|
915
|
+
# Let's bounce to our page that will give us our short term cookie, URL has Kerbrose style ticket.
|
916
|
+
return login_final_bounce(stage1.header['location'])
|
917
|
+
end
|
918
|
+
|
919
|
+
# Finally we didn't get 302 or 200?
|
920
|
+
raise Wowr::Exceptions::LoginBroken
|
921
|
+
end
|
922
|
+
|
923
|
+
# Clear the cache, optional directory name.
|
924
|
+
# * cache_path (String) Relative path of the cache directory to be deleted
|
925
|
+
def clear_cache(cache_path = @@cache_directory_path)
|
926
|
+
begin
|
927
|
+
FileUtils.remove_dir(cache_path)
|
928
|
+
rescue Exception => e
|
929
|
+
|
930
|
+
end
|
931
|
+
end
|
932
|
+
|
933
|
+
|
934
|
+
# Return the base url for the armory, e.g. http://eu.wowarmory.com/
|
935
|
+
# * locale (String) The locale, defaults to that specified in the API constructor
|
936
|
+
def base_url(locale = @locale, options = {})
|
937
|
+
str = ""
|
938
|
+
|
939
|
+
if (options[:secure] == true)
|
940
|
+
str += 'https://'
|
941
|
+
else
|
942
|
+
str += 'http://'
|
943
|
+
end
|
944
|
+
|
945
|
+
if (locale == 'us')
|
946
|
+
str += 'www.'
|
947
|
+
else
|
948
|
+
str += locale + "."
|
949
|
+
end
|
950
|
+
|
951
|
+
if (options[:login] == true)
|
952
|
+
str += @@login_base_url
|
953
|
+
else
|
954
|
+
str += @@armory_base_url
|
955
|
+
end
|
956
|
+
|
957
|
+
return str
|
958
|
+
end
|
959
|
+
|
960
|
+
|
961
|
+
protected
|
962
|
+
|
963
|
+
# Merge the defaults specified in the constructor with those supplied,
|
964
|
+
# overriding any defaults with those supplied
|
965
|
+
def merge_defaults(options = {})
|
966
|
+
defaults = {}
|
967
|
+
# defaults[:character_name] = @charater_name if @charater_name
|
968
|
+
# defaults[:guild_name] = @guild_name if @guild_name
|
969
|
+
defaults[:realm] = @realm if @realm
|
970
|
+
defaults[:locale] = @locale if @locale
|
971
|
+
defaults[:lang] = @lang if @lang
|
972
|
+
defaults[:caching] = @caching if @caching
|
973
|
+
defaults[:cache_timeout] = @cache_timeout if @cache_timeout
|
974
|
+
defaults[:debug] = @debug if @debug
|
975
|
+
|
976
|
+
# overwrite defaults with any given options
|
977
|
+
defaults.merge!(options)
|
978
|
+
end
|
979
|
+
|
980
|
+
# Returns an option array from character_name and defaults
|
981
|
+
def character_options(name, options = {})
|
982
|
+
if (name.is_a?(Hash))
|
983
|
+
options = name
|
984
|
+
else
|
985
|
+
options.merge!(:character_name => name)
|
986
|
+
|
987
|
+
# TODO check
|
988
|
+
options = {:character_name => @character_name}.merge(options) if (!@character_name.nil?)
|
989
|
+
end
|
990
|
+
|
991
|
+
options = merge_defaults(options)
|
992
|
+
|
993
|
+
if options[:character_name].nil? || options[:chracter_name] == ""
|
994
|
+
raise Wowr::Exceptions::CharacterNameNotSet.new
|
995
|
+
elsif options[:realm].nil? || options[:realm] == ""
|
996
|
+
raise Wowr::Exceptions::RealmNotSet.new
|
997
|
+
end
|
998
|
+
|
999
|
+
return options
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
|
1003
|
+
# Return an Hpricot document for the given URL
|
1004
|
+
def get_xml(url, options = {})
|
1005
|
+
response = get_file(url, options)
|
1006
|
+
doc = Hpricot.XML(response)
|
1007
|
+
errors = doc.search("*[@errCode]")
|
1008
|
+
if errors.size > 0
|
1009
|
+
errors.each do |error|
|
1010
|
+
raise Wowr::Exceptions::raise_me(error[:errCode], options)
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
elsif (doc%'achievements')
|
1014
|
+
return doc
|
1015
|
+
elsif (doc%'dungeons')
|
1016
|
+
return doc
|
1017
|
+
elsif (doc%'page').nil?
|
1018
|
+
raise Wowr::Exceptions::EmptyPage
|
1019
|
+
else
|
1020
|
+
return (doc%'page')
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
# Return an array of hashes for the given URL
|
1025
|
+
def get_json(url, options = {})
|
1026
|
+
response = get_file(url, options)
|
1027
|
+
raw_json = response.scan(/\w+\((.+)\);\z/)[0][0]
|
1028
|
+
return JSON.parse(raw_json)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
|
1032
|
+
# Return an raw document for the given URL
|
1033
|
+
# TODO: Tidy up?
|
1034
|
+
def get_file(url, options = {})
|
1035
|
+
|
1036
|
+
# better way of doing this?
|
1037
|
+
# Map custom keys to the HTTP request values
|
1038
|
+
reqs = {
|
1039
|
+
:character_name => 'n',
|
1040
|
+
:realm => 'r',
|
1041
|
+
:search => 'searchQuery',
|
1042
|
+
:type => 'searchType',
|
1043
|
+
:guild_name => 'gn',
|
1044
|
+
:item_id => 'i',
|
1045
|
+
:team_size => 'ts',
|
1046
|
+
:team_name => 't',
|
1047
|
+
:group => 'group',
|
1048
|
+
:callback => 'callback',
|
1049
|
+
:calendar_type => 'type',
|
1050
|
+
:month => 'month',
|
1051
|
+
:year => 'year',
|
1052
|
+
:event => 'e',
|
1053
|
+
:now => 'now',
|
1054
|
+
:achievement_category => 'c'
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
params = []
|
1058
|
+
options.each do |key, value|
|
1059
|
+
params << "#{reqs[key]}=#{u(value)}" if reqs[key]
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
query = ''
|
1063
|
+
query = query + '?' + params.join('&') if params.size > 0
|
1064
|
+
#query = '?' + params.join('&') if params.size > 0
|
1065
|
+
|
1066
|
+
base = self.base_url(options[:locale], options)
|
1067
|
+
full_query = base + url + query
|
1068
|
+
|
1069
|
+
if options[:caching]
|
1070
|
+
response = get_cache(full_query, options)
|
1071
|
+
else
|
1072
|
+
response = http_request(full_query, options)
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
|
1077
|
+
# Perform an HTTP request and return the contents of the document
|
1078
|
+
def http_request(url, options = {})
|
1079
|
+
req = Net::HTTP::Get.new(url)
|
1080
|
+
req["user-agent"] = @@user_agent # ensure returns XML
|
1081
|
+
req["cookie"] = "cookieMenu=all; cookieLangId=" + options[:lang] + "; cookies=true;"
|
1082
|
+
|
1083
|
+
req["cookie"] += options[:cookie] if options[:cookie]
|
1084
|
+
|
1085
|
+
uri = URI.parse(url)
|
1086
|
+
|
1087
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
1088
|
+
|
1089
|
+
if (options[:secure])
|
1090
|
+
puts "Secure authentication" if options[:debug]
|
1091
|
+
|
1092
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
1093
|
+
http.use_ssl = true
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
|
1097
|
+
begin
|
1098
|
+
tries = 0
|
1099
|
+
http.start do
|
1100
|
+
puts "Get URL "+url if options[:debug]
|
1101
|
+
res = http.request req
|
1102
|
+
# response = res.body
|
1103
|
+
|
1104
|
+
response = case res
|
1105
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
1106
|
+
res.body
|
1107
|
+
else
|
1108
|
+
tries += 1
|
1109
|
+
if tries > @@max_connection_tries
|
1110
|
+
raise Wowr::Exceptions::NetworkTimeout.new('Timed out')
|
1111
|
+
else
|
1112
|
+
retry
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
rescue Timeout::Error => e
|
1117
|
+
raise Wowr::Exceptions::NetworkTimeout.new('Timed out - Timeout::Error Exception')
|
1118
|
+
rescue Net::HTTPExceptions => e
|
1119
|
+
raise Wowr::Exceptions::ServerDoesNotExist.new('Specified server at ' + url + ' does not exist.')
|
1120
|
+
end
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
|
1124
|
+
# Translate the specified URL to the cache location, and return the file
|
1125
|
+
# If the cache does not exist, get the contents using http_request and create it
|
1126
|
+
def get_cache(url, options = {})
|
1127
|
+
path = cache_path(url, options)
|
1128
|
+
|
1129
|
+
# file doesn't exist, make it
|
1130
|
+
if !File.exists?(path) ||
|
1131
|
+
options[:refresh_cache] ||
|
1132
|
+
(File.mtime(path) < Time.now - @cache_timeout)
|
1133
|
+
|
1134
|
+
if options[:debug]
|
1135
|
+
if !File.exists?(path)
|
1136
|
+
puts 'Cache doesn\'t exist, making: ' + path
|
1137
|
+
elsif (File.mtime(path) < Time.now - @cache_timeout)
|
1138
|
+
puts 'Cache has expired, making again, making: ' + path
|
1139
|
+
elsif options[:refresh_cache]
|
1140
|
+
puts 'Forced refresh of cache, making: ' + path
|
1141
|
+
end
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
# make sure dir exists
|
1145
|
+
FileUtils.mkdir_p(localised_cache_path(options[:lang])) unless File.directory?(localised_cache_path(options[:lang]))
|
1146
|
+
|
1147
|
+
xml_content = http_request(url, options)
|
1148
|
+
|
1149
|
+
# write the cache
|
1150
|
+
file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT)
|
1151
|
+
file.write(xml_content)
|
1152
|
+
file.close
|
1153
|
+
|
1154
|
+
# file exists, return the contents
|
1155
|
+
else
|
1156
|
+
puts 'Cache already exists, read: ' + path if options[:debug]
|
1157
|
+
|
1158
|
+
file = File.open(path, 'r')
|
1159
|
+
xml_content = file.read
|
1160
|
+
file.close
|
1161
|
+
end
|
1162
|
+
return xml_content
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
|
1166
|
+
def cache_path(url, options)
|
1167
|
+
@@cache_directory_path + options[:lang] + '/' + url_to_filename(url)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
|
1171
|
+
# remove http://*.wowarmory.com/ leaving just xml file part and request parameters
|
1172
|
+
# Kind of assuming incoming URL is the same as the current locale
|
1173
|
+
def url_to_filename(url) #:nodoc:
|
1174
|
+
temp = url.gsub(base_url(), '')
|
1175
|
+
temp.gsub!('/', '.')
|
1176
|
+
return temp
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
|
1180
|
+
|
1181
|
+
def localised_cache_path(lang = @lang) #:nodoc:
|
1182
|
+
return @@cache_directory_path + lang
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
|
1186
|
+
|
1187
|
+
def u(str) #:nodoc:
|
1188
|
+
if str.instance_of?(String)
|
1189
|
+
return CGI.escape(str)
|
1190
|
+
else
|
1191
|
+
return str
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def login_final_bounce(url)
|
1196
|
+
# Let's bounce to our page that will give us our short term cookie, URL has Kerbrose style ticket.
|
1197
|
+
finalstage = login_http(url)
|
1198
|
+
|
1199
|
+
# Did we get a 200?
|
1200
|
+
if (finalstage.code == "200")
|
1201
|
+
# Get the short term cookie at last
|
1202
|
+
short_cookie = nil
|
1203
|
+
finalstage.header['set-cookie'].scan(/#{@@temporary_cookie}=(.*?);/) {
|
1204
|
+
short_cookie = $1
|
1205
|
+
}
|
1206
|
+
|
1207
|
+
return short_cookie
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
# Finally we didn't get 200?
|
1211
|
+
raise Wowr::Exceptions::LoginBroken
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
def login_http(url, ssl = false, cookie = nil, data = nil, post = false)
|
1215
|
+
if (post)
|
1216
|
+
req = Net::HTTP::Post.new(url)
|
1217
|
+
else
|
1218
|
+
req = Net::HTTP::Get.new(url)
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
req["user-agent"] = "Mozilla/5.0 Gecko/20070219 Firefox/2.0.0.2" # ensure returns XML
|
1222
|
+
req["cookie"] = "cookieMenu=all; cookies=true;"
|
1223
|
+
req["cookie"] += cookie.collect { |key, value| "#{key}=#{value};"}.join(" ") if cookie
|
1224
|
+
|
1225
|
+
uri = URI.parse(url)
|
1226
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
1227
|
+
|
1228
|
+
if (ssl)
|
1229
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
1230
|
+
http.use_ssl = true
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
req.set_form_data(data, '&') if data
|
1234
|
+
|
1235
|
+
http.start do
|
1236
|
+
res = http.request(req)
|
1237
|
+
|
1238
|
+
tries = 0
|
1239
|
+
response = case res
|
1240
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
1241
|
+
return res
|
1242
|
+
else
|
1243
|
+
tries += 1
|
1244
|
+
if tries > @@max_connection_tries
|
1245
|
+
raise Wowr::Exceptions::NetworkTimeout.new('Timed out')
|
1246
|
+
else
|
1247
|
+
retry
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
end
|
1253
|
+
end
|