brickset_api 0.1.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.
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