brickset_api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +145 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/brickset.gemspec +30 -0
  13. data/lib/brickset.rb +55 -0
  14. data/lib/brickset/api/auth.rb +22 -0
  15. data/lib/brickset/api/collection/advanced.rb +34 -0
  16. data/lib/brickset/api/collection/minifig.rb +35 -0
  17. data/lib/brickset/api/collection/set.rb +117 -0
  18. data/lib/brickset/api/set.rb +157 -0
  19. data/lib/brickset/client.rb +56 -0
  20. data/lib/brickset/configuration.rb +9 -0
  21. data/lib/brickset/elements/additional_image.rb +13 -0
  22. data/lib/brickset/elements/collection_detail.rb +28 -0
  23. data/lib/brickset/elements/collection_total.rb +15 -0
  24. data/lib/brickset/elements/condition.rb +11 -0
  25. data/lib/brickset/elements/instruction.rb +12 -0
  26. data/lib/brickset/elements/minifig_collection.rb +15 -0
  27. data/lib/brickset/elements/review.rb +20 -0
  28. data/lib/brickset/elements/set.rb +67 -0
  29. data/lib/brickset/elements/subtheme.rb +15 -0
  30. data/lib/brickset/elements/theme.rb +15 -0
  31. data/lib/brickset/elements/user_note.rb +12 -0
  32. data/lib/brickset/elements/year.rb +13 -0
  33. data/lib/brickset/version.rb +3 -0
  34. data/spec/brickset/api/auth_spec.rb +84 -0
  35. data/spec/brickset/api/collection/advanced_spec.rb +59 -0
  36. data/spec/brickset/api/collection/minifig_spec.rb +95 -0
  37. data/spec/brickset/api/collection/set_spec.rb +350 -0
  38. data/spec/brickset/api/set_spec.rb +658 -0
  39. data/spec/brickset/client_spec.rb +155 -0
  40. data/spec/brickset/configuration_spec.rb +9 -0
  41. data/spec/brickset/elements/additional_image_spec.rb +26 -0
  42. data/spec/brickset/elements/collection_detail_spec.rb +40 -0
  43. data/spec/brickset/elements/collection_total_spec.rb +27 -0
  44. data/spec/brickset/elements/condition_spec.rb +23 -0
  45. data/spec/brickset/elements/instruction_spec.rb +24 -0
  46. data/spec/brickset/elements/minifig_collection_spec.rb +27 -0
  47. data/spec/brickset/elements/review_spec.rb +32 -0
  48. data/spec/brickset/elements/set_spec.rb +72 -0
  49. data/spec/brickset/elements/subtheme_spec.rb +27 -0
  50. data/spec/brickset/elements/theme_spec.rb +27 -0
  51. data/spec/brickset/elements/user_note_spec.rb +24 -0
  52. data/spec/brickset/elements/year_spec.rb +25 -0
  53. data/spec/brickset_spec.rb +59 -0
  54. data/spec/fixtures/api_key_invalid.xml +2 -0
  55. data/spec/fixtures/api_key_valid.xml +2 -0
  56. data/spec/fixtures/get_additional_images.xml +24 -0
  57. data/spec/fixtures/get_additional_images_no_result.xml +2 -0
  58. data/spec/fixtures/get_collection_detail.xml +23 -0
  59. data/spec/fixtures/get_collection_detail_conditions.xml +24 -0
  60. data/spec/fixtures/get_collection_detail_no_result.xml +2 -0
  61. data/spec/fixtures/get_collection_totals.xml +8 -0
  62. data/spec/fixtures/get_collection_totals_no_result.xml +8 -0
  63. data/spec/fixtures/get_instructions.xml +7 -0
  64. data/spec/fixtures/get_instructions_no_result.xml +2 -0
  65. data/spec/fixtures/get_minifig_collection.xml +31 -0
  66. data/spec/fixtures/get_minifig_collection_owned.xml +17 -0
  67. data/spec/fixtures/get_minifig_collection_wanted.xml +10 -0
  68. data/spec/fixtures/get_recently_updated_sets.xml +52 -0
  69. data/spec/fixtures/get_recently_updated_sets_invalid_key.xml +1 -0
  70. data/spec/fixtures/get_reviews.xml +28 -0
  71. data/spec/fixtures/get_reviews_no_result.xml +2 -0
  72. data/spec/fixtures/get_set.xml +52 -0
  73. data/spec/fixtures/get_set_no_result.xml +2 -0
  74. data/spec/fixtures/get_sets.xml +101 -0
  75. data/spec/fixtures/get_sets_no_result.xml +2 -0
  76. data/spec/fixtures/get_subthemes.xml +24 -0
  77. data/spec/fixtures/get_subthemes_for_user.xml +24 -0
  78. data/spec/fixtures/get_subthemes_for_user_no_result.xml +2 -0
  79. data/spec/fixtures/get_subthemes_for_user_owned.xml +24 -0
  80. data/spec/fixtures/get_subthemes_for_user_wanted.xml +31 -0
  81. data/spec/fixtures/get_subthemes_no_result.xml +2 -0
  82. data/spec/fixtures/get_themes.xml +17 -0
  83. data/spec/fixtures/get_themes_for_user.xml +17 -0
  84. data/spec/fixtures/get_themes_for_user_no_result.xml +2 -0
  85. data/spec/fixtures/get_themes_for_user_owned.xml +17 -0
  86. data/spec/fixtures/get_themes_for_user_wanted.xml +25 -0
  87. data/spec/fixtures/get_themes_no_result.xml +2 -0
  88. data/spec/fixtures/get_user_notes.xml +11 -0
  89. data/spec/fixtures/get_user_notes_no_result.xml +2 -0
  90. data/spec/fixtures/get_years.xml +18 -0
  91. data/spec/fixtures/get_years_for_user.xml +18 -0
  92. data/spec/fixtures/get_years_for_user_no_result.xml +2 -0
  93. data/spec/fixtures/get_years_for_user_owned.xml +13 -0
  94. data/spec/fixtures/get_years_for_user_wanted.xml +13 -0
  95. data/spec/fixtures/get_years_no_result.xml +2 -0
  96. data/spec/fixtures/login.xml +2 -0
  97. data/spec/fixtures/login_invalid_credentials.xml +2 -0
  98. data/spec/fixtures/login_invalid_key.xml +2 -0
  99. data/spec/fixtures/set_collection.xml +2 -0
  100. data/spec/fixtures/set_collection_invalid.xml +2 -0
  101. data/spec/fixtures/set_collection_owns.xml +2 -0
  102. data/spec/fixtures/set_collection_owns_invalid.xml +2 -0
  103. data/spec/fixtures/set_collection_qty_owned.xml +2 -0
  104. data/spec/fixtures/set_collection_qty_owned_invalid.xml +2 -0
  105. data/spec/fixtures/set_collection_user_notes.xml +2 -0
  106. data/spec/fixtures/set_collection_user_notes_invalid.xml +2 -0
  107. data/spec/fixtures/set_collection_wants.xml +2 -0
  108. data/spec/fixtures/set_collection_wants_invalid.xml +2 -0
  109. data/spec/fixtures/set_minifig_collection.xml +2 -0
  110. data/spec/fixtures/set_minifig_collection_invalid.xml +2 -0
  111. data/spec/fixtures/set_user_rating.xml +2 -0
  112. data/spec/fixtures/set_user_rating_invalid.xml +2 -0
  113. data/spec/fixtures/token_invalid.xml +2 -0
  114. data/spec/fixtures/token_valid.xml +2 -0
  115. data/spec/spec_helper.rb +43 -0
  116. metadata +355 -0
@@ -0,0 +1,157 @@
1
+ module Brickset
2
+ module Api
3
+ module Set
4
+ extend ActiveSupport::Concern
5
+
6
+ module Order
7
+ module Types
8
+ NUMBER = 'number'
9
+ NAME = 'name'
10
+ THEME = 'theme'
11
+ PIECES = 'pieces'
12
+ RATING = 'rating'
13
+ SUBTHEME = 'subtheme'
14
+ MINIFIGS = 'minifigs'
15
+ YEAR_FROM = 'yearfrom'
16
+ RETAIL_PRICE_UK = 'ukretailprice'
17
+ RETAIL_PRICE_US = 'usretailprice'
18
+ RETAIL_PRICE_CA = 'caretailprice'
19
+ RETAIL_PRICE_EU = 'euretailprice'
20
+ RANDOM = 'random'
21
+ ALL = constants(false).map { |constant| const_get(constant) }
22
+ end
23
+
24
+ module Direction
25
+ ASC = 'asc'
26
+ DESC = 'desc'
27
+ ALL = constants(false).map { |constant| const_get(constant) }
28
+ end
29
+ end
30
+
31
+ included do
32
+ attr_accessor :set_number, :year, :page_size, :page_number, :order_by, :order_direction, :set_id, :minutes_ago
33
+
34
+ with_options(on: :sets) do |options|
35
+ options.validates :set_number, format: { with: /\A\w+-\d+\z/, message: 'format of <number>-<variant>, e.g. 75192-1 or darthvader-1' }, allow_blank: true
36
+ options.validates :page_size, :page_number, numericality: { only_integer: true }
37
+ options.validates :order_by, inclusion: { in: Order::Types::ALL }
38
+ options.validates :order_direction, inclusion: { in: Order::Direction::ALL }
39
+ end
40
+
41
+ validates :set_id, numericality: { only_integer: true }, on: [:set, :additional_images, :reviews, :instructions]
42
+ validates :minutes_ago, numericality: { only_integer: true }, on: :recently_updated_sets
43
+ end
44
+
45
+ def sets(query: '', theme: '', subtheme: '', set_number: '', year: '', owned: '', wanted: '', order_by: 'number', page_size: 20, page_number: 1, username: '', order_direction: Order::Direction::ASC)
46
+ self.set_number = set_number
47
+ self.page_size = page_size
48
+ self.page_number = page_number
49
+ self.order_by = order_by
50
+ self.order_direction = order_direction
51
+
52
+ if valid?(:sets)
53
+ # NOTE: all of the parameters are required, even though the API specifies them as optional.
54
+ xml = call('/getSets', query: query, theme: theme, subtheme: subtheme, setNumber: set_number, year: year, owned: owned, wanted: wanted, orderBy: order, pageSize: page_size, pageNumber: page_number, userName: username)
55
+ Brickset::Elements::Set.parse(xml)
56
+ else
57
+ raise ValidationError, self.errors.full_messages.to_sentence
58
+ end
59
+ end
60
+
61
+ def set(set_id)
62
+ self.set_id = set_id
63
+
64
+ if valid?(:set)
65
+ xml = call('/getSet', setID: set_id)
66
+ Brickset::Elements::Set.parse(xml, single: true)
67
+ else
68
+ raise ValidationError, self.errors.full_messages.to_sentence
69
+ end
70
+ end
71
+
72
+ def recently_updated_sets(minutes_ago)
73
+ self.minutes_ago = minutes_ago
74
+
75
+ if valid?(:recently_updated_sets)
76
+ xml = call('/getRecentlyUpdatedSets', minutesAgo: minutes_ago)
77
+ Brickset::Elements::Set.parse(xml)
78
+ else
79
+ raise ValidationError, self.errors.full_messages.to_sentence
80
+ end
81
+ end
82
+
83
+ def additional_images(set_id)
84
+ self.set_id = set_id
85
+
86
+ if valid?(:additional_images)
87
+ xml = call('/getAdditionalImages', setID: set_id)
88
+ Brickset::Elements::AdditionalImage.parse(xml)
89
+ else
90
+ raise ValidationError, self.errors.full_messages.to_sentence
91
+ end
92
+ end
93
+
94
+ def reviews(set_id)
95
+ self.set_id = set_id
96
+
97
+ if valid?(:reviews)
98
+ xml = call('/getReviews', setID: set_id)
99
+ Brickset::Elements::Review.parse(xml)
100
+ else
101
+ raise ValidationError, self.errors.full_messages.to_sentence
102
+ end
103
+ end
104
+
105
+ def instructions(set_id)
106
+ self.set_id = set_id
107
+
108
+ if valid?(:instructions)
109
+ xml = call('/getInstructions', setID: set_id)
110
+ Brickset::Elements::Instruction.parse(xml)
111
+ else
112
+ raise ValidationError, self.errors.full_messages.to_sentence
113
+ end
114
+ end
115
+
116
+ def themes
117
+ xml = call('/getThemes')
118
+ Brickset::Elements::Theme.parse(xml)
119
+ end
120
+
121
+ def subthemes(theme)
122
+ xml = call('/getSubthemes', theme: theme)
123
+ Brickset::Elements::Subtheme.parse(xml)
124
+ end
125
+
126
+ def years(theme)
127
+ xml = call('/getYears', theme: theme)
128
+ Brickset::Elements::Year.parse(xml)
129
+ end
130
+
131
+ def themes_for_user(owned: '', wanted: '')
132
+ xml = call('/getThemesForUser', owned: owned, wanted: wanted)
133
+ Brickset::Elements::Theme.parse(xml)
134
+ end
135
+
136
+ def subthemes_for_user(theme, owned: '', wanted: '')
137
+ xml = call('/getSubthemesForUser', theme: theme, owned: owned, wanted: wanted)
138
+ Brickset::Elements::Subtheme.parse(xml)
139
+ end
140
+
141
+ def years_for_user(theme, owned: '', wanted: '')
142
+ xml = call('/getYearsForUser', theme: theme, owned: owned, wanted: wanted)
143
+ Brickset::Elements::Year.parse(xml)
144
+ end
145
+
146
+ private
147
+
148
+ def order
149
+ if order_direction == Order::Direction::DESC
150
+ [ order_by, order_direction.upcase ].join
151
+ else
152
+ order_by
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,56 @@
1
+ module Brickset
2
+ class Client
3
+ include HTTParty
4
+ include ActiveModel::Validations
5
+
6
+ include Brickset::Api::Auth
7
+ include Brickset::Api::Set
8
+ include Brickset::Api::Collection::Set
9
+ include Brickset::Api::Collection::Minifig
10
+ include Brickset::Api::Collection::Advanced
11
+
12
+ base_uri Brickset::BASE_URI
13
+
14
+ attr_reader :token
15
+
16
+ def initialize(options = {})
17
+ @token = options[:token] if options.key?(:token)
18
+ end
19
+
20
+ private
21
+
22
+ def call(method, options = {})
23
+ response = self.class.post(method, { body: options.merge(default_options) })
24
+
25
+ if response.code == 200
26
+ response.body
27
+ else
28
+ raise response.body
29
+ end
30
+ end
31
+
32
+ def handle_update(response)
33
+ content = HappyMapper.parse(response).content
34
+
35
+ if content == 'OK'
36
+ true
37
+ else
38
+ errors.add(:base, content)
39
+ false
40
+ end
41
+ end
42
+
43
+ def extract_attributes_from_options(options)
44
+ options.each do |key, value|
45
+ raise KeyError, "Attribute key '#{key}' is not supported" unless respond_to?("#{key}=")
46
+ send("#{key}=", value)
47
+ end
48
+ end
49
+
50
+ def default_options
51
+ options = { apiKey: Brickset.configuration.api_key }
52
+ options.merge!(userHash: token) if token
53
+ options
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,9 @@
1
+ module Brickset
2
+ class Configuration
3
+ attr_accessor :api_key
4
+
5
+ def initialize
6
+ @api_key = nil
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Brickset
2
+ module Elements
3
+ class AdditionalImage
4
+ include HappyMapper
5
+
6
+ tag 'additionalImages'
7
+
8
+ element :thumbnail_url, String, tag: 'thumbnailURL'
9
+ element :thumbnail_url_large, String, tag: 'largeThumbnailURL'
10
+ element :image_url, String, tag: 'imageURL'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module Brickset
2
+ module Elements
3
+ class CollectionDetail
4
+ include HappyMapper
5
+
6
+ tag 'collectionDetails'
7
+
8
+ element :collection_id, Integer, tag: 'collectionID'
9
+ element :date_acquired, String, tag: 'dateAcquired'
10
+ element :currency, String
11
+ element :price_paid, Float, tag: 'pricePaid'
12
+ element :additional_price_paid, Float, tag: 'additionalPricePaid'
13
+ element :current_estimated_value, Float, tag: 'currentEstimatedValue'
14
+ element :condition_when_acquired, String, tag: 'conditionWhenAcquired'
15
+ element :acquired_from, String, tag: 'acquiredFrom'
16
+ element :condition_now, String, tag: 'conditionNow'
17
+ element :location, String
18
+ element :notes, String
19
+ element :parts, Boolean
20
+ element :minifigs, Boolean
21
+ element :instructions, Boolean
22
+ element :box, Boolean
23
+ element :modified, Boolean
24
+ element :will_trade, Boolean, tag: 'willTrade'
25
+ element :deleted, Boolean
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ module Brickset
2
+ module Elements
3
+ class CollectionTotal
4
+ include HappyMapper
5
+
6
+ tag 'collectionTotals'
7
+
8
+ element :total_sets_owned, Integer, tag: 'totalSetsOwned'
9
+ element :total_sets_wanted, Integer, tag: 'totalSetsWanted'
10
+ element :total_distinct_sets_owned, Integer, tag: 'totalDistinctSetsOwned'
11
+ element :total_minifigs_owned, Integer, tag: 'totalMinifigsOwned'
12
+ element :total_minifigs_wanted, Integer, tag: 'totalMinifigsWanted'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Brickset
2
+ module Elements
3
+ class Condition
4
+ include HappyMapper
5
+
6
+ tag 'conditions'
7
+
8
+ element :condition, String
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Brickset
2
+ module Elements
3
+ class Instruction
4
+ include HappyMapper
5
+
6
+ tag 'instructions'
7
+
8
+ element :url, String, tag: 'URL'
9
+ element :description, String
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module Brickset
2
+ module Elements
3
+ class MinifigCollection
4
+ include HappyMapper
5
+
6
+ tag 'minifigCollection'
7
+
8
+ element :minifig_number, String, tag: 'minifigNumber'
9
+ element :owned_in_sets, Integer, tag: 'ownedInSets'
10
+ element :owned_loose, Integer, tag: 'ownedLoose'
11
+ element :owned_total, Integer, tag: 'ownedTotal'
12
+ element :wanted, Boolean
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module Brickset
2
+ module Elements
3
+ class Review
4
+ include HappyMapper
5
+
6
+ tag 'reviews'
7
+
8
+ element :author, String
9
+ element :title, String
10
+ element :review, String
11
+ element :date_posted, Date, tag: 'datePosted'
12
+ element :overall_rating, Integer, tag: 'overallRating'
13
+ element :parts, Integer
14
+ element :building_experience, Integer, tag: 'buildingExperience'
15
+ element :playability, Integer
16
+ element :value_for_money, Integer, tag: 'valueForMoney'
17
+ element :html, Boolean, tag: 'HTML'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ module Brickset
2
+ module Elements
3
+ class Set
4
+ include HappyMapper
5
+
6
+ tag 'sets'
7
+
8
+ element :id, Integer, tag: 'setID'
9
+ element :number, String
10
+ element :number_variant, Integer, tag: 'numberVariant'
11
+ element :name, String
12
+ element :year, String
13
+ element :description, String
14
+ element :category, String
15
+ element :theme, String
16
+ element :theme_group, String, tag: 'themeGroup'
17
+ element :subtheme, String, tag: 'subtheme'
18
+ element :pieces, String
19
+ element :minifigs, String
20
+ element :image, Boolean
21
+ element :image_url, String, tag: 'imageURL'
22
+ element :image_filename, String, tag: 'imageFilename'
23
+ element :thumbnail_url, String, tag: 'thumbnailURL'
24
+ element :thumbnail_url_large, String, tag: 'largeThumbnailURL'
25
+ element :brickset_url, String, tag: 'bricksetURL'
26
+ element :owned_by_total, Integer, tag: 'ownedByTotal'
27
+ element :wanted_by_total, Integer, tag: 'wantedByTotal'
28
+ element :released, Boolean
29
+ element :rating, Float
30
+ element :user_rating, Integer, tag: 'userRating'
31
+ element :review_count, Integer, tag: 'reviewCount'
32
+ element :instructions_count, Integer, tag: 'instructionsCount'
33
+ element :additional_image_count, Integer, tag: 'additionalImageCount'
34
+ element :last_updated, Date, tag: 'lastUpdated'
35
+ element :age_minimum, Integer, tag: 'ageMin'
36
+ element :age_maximum, Integer, tag: 'ageMax'
37
+ element :notes, String
38
+ element :tags, String
39
+
40
+ # retail related.
41
+
42
+ element :retail_price_uk, String, tag: 'UKRetailPrice'
43
+ element :retail_price_us, String, tag: 'USRetailPrice'
44
+ element :retail_price_ca, String, tag: 'CARetailPrice'
45
+ element :retail_price_eu, String, tag: 'EURetailPrice'
46
+ element :date_added_to_shop, String, tag: 'USDateAddedToSAH'
47
+ element :date_removed_from_shop, String, tag: 'USDateRemovedFromSAH'
48
+ element :packaging_type, String, tag: 'packagingType'
49
+ element :height, Float
50
+ element :width, Float
51
+ element :depth, Float
52
+ element :weight, Float
53
+ element :availability, String
54
+ element :ean, String, tag: 'EAN'
55
+ element :upc, String, tag: 'UPC'
56
+
57
+ element :acm_data_count, Integer, tag: 'ACMDataCount'
58
+
59
+ # requires authentication.
60
+
61
+ element :owned, Boolean
62
+ element :wanted, Boolean
63
+ element :number_owned, Integer, tag: 'qtyOwned'
64
+ element :user_notes, String, tag: 'userNotes'
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,15 @@
1
+ module Brickset
2
+ module Elements
3
+ class Subtheme
4
+ include HappyMapper
5
+
6
+ tag 'subthemes'
7
+
8
+ element :theme, String
9
+ element :subtheme, String
10
+ element :set_count, Integer, tag: 'setCount'
11
+ element :year_from, Integer, tag: 'yearFrom'
12
+ element :year_to, Integer, tag: 'yearTo'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Brickset
2
+ module Elements
3
+ class Theme
4
+ include HappyMapper
5
+
6
+ tag 'themes'
7
+
8
+ element :theme, String
9
+ element :set_count, Integer, tag: 'setCount'
10
+ element :subtheme_count, Integer, tag: 'subthemeCount'
11
+ element :year_from, Integer, tag: 'yearFrom'
12
+ element :year_to, Integer, tag: 'yearTo'
13
+ end
14
+ end
15
+ end