wikidatum 0.2.1 → 0.3.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +24 -2
- data/lib/wikidatum/client.rb +137 -54
- data/lib/wikidatum/data_type/base.rb +61 -0
- data/lib/wikidatum/{data_value_type → data_type}/globe_coordinate.rb +21 -20
- data/lib/wikidatum/{data_value_type → data_type}/monolingual_text.rb +19 -18
- data/lib/wikidatum/{data_value_type → data_type}/no_value.rb +3 -11
- data/lib/wikidatum/data_type/quantity.rb +75 -0
- data/lib/wikidatum/{data_value_type → data_type}/some_value.rb +3 -11
- data/lib/wikidatum/{data_value_type → data_type}/time.rb +20 -37
- data/lib/wikidatum/data_type/wikibase_item.rb +62 -0
- data/lib/wikidatum/{data_value_type → data_type}/wikibase_string.rb +16 -15
- data/lib/wikidatum/data_type.rb +11 -0
- data/lib/wikidatum/item.rb +2 -2
- data/lib/wikidatum/qualifier.rb +52 -4
- data/lib/wikidatum/reference.rb +9 -9
- data/lib/wikidatum/reference_part.rb +56 -0
- data/lib/wikidatum/statement.rb +21 -11
- data/lib/wikidatum/utils.rb +25 -0
- data/lib/wikidatum/version.rb +1 -1
- data/lib/wikidatum.rb +32 -12
- metadata +15 -14
- data/lib/wikidatum/data_value_type/base.rb +0 -61
- data/lib/wikidatum/data_value_type/quantity.rb +0 -92
- data/lib/wikidatum/data_value_type/wikibase_entity_id.rb +0 -83
- data/lib/wikidatum/data_value_type.rb +0 -11
- data/lib/wikidatum/snak.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2ee435a3831b816e6e64465040a5197de654450551812b835b28329be9c287d
|
4
|
+
data.tar.gz: d23fb1902df5465b123fc0bcea0c7594fb64a6e918604a9f1bb1f4e4eadf6eff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccd8210a5120fbbfb35ed03899938bf4ca4e5302bc93e3e53652180b86b221a3ec23afe57db78777ffcda5971150f7c0ed6af89cde7b294fe21d716491653c49
|
7
|
+
data.tar.gz: cb4e092b80c6ab871c1dd7f5bd46f700029eab7438c7a4063a2aee42b389c0e86ec0e387fc15fa996037d2478f494ac46572879078930c41c18ae6b7e4073e00
|
data/CHANGELOG.md
CHANGED
@@ -6,8 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
|
7
7
|
## Unreleased
|
8
8
|
|
9
|
+
## 0.3.1 - 2022-12-28
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Add an error message when attempting to make a bot edit without authentication, as this will always trigger a 403 error from the REST API.
|
13
|
+
|
14
|
+
### Fixed
|
15
|
+
|
16
|
+
- Fix the creation of WikibaseItem statements, the format used in the previous release was incorrect.
|
17
|
+
|
18
|
+
## 0.3.0 - 2022-12-27
|
19
|
+
### Added
|
20
|
+
|
21
|
+
- Add `allow_ip_edits` argument on `Wikidatum::Client.new`. This protects users from making IP address-exposing edits if they haven't explicitly opted-in to doing that. The argument defaults to false.
|
22
|
+
- Add code to raise errors when various types of invalid input are passed to `Wikidatum::Client#add_statement`.
|
23
|
+
- Start testing the gem on Ruby 3.2.
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
|
27
|
+
- Update the serializers and `add_statement` method to account for various changes that have been made upstream to the Wikibase REST API.
|
28
|
+
|
9
29
|
## 0.2.1 - 2022-08-13
|
10
30
|
### Fixed
|
31
|
+
|
11
32
|
- Fix a mistake that broke loading the gem.
|
12
33
|
|
13
34
|
## 0.2.0 - 2022-08-13
|
@@ -28,4 +49,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
28
49
|
### Added
|
29
50
|
|
30
51
|
- Initial release, nothing is really usable yet.
|
31
|
-
|
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
This gem supports making requests to the [new Wikidata/Wikibase REST API](https://doc.wikimedia.org/Wikibase/master/js/rest-api/).
|
4
4
|
|
5
|
-
|
5
|
+
The [Wikimedia Docs on Wikibase's JSON format](https://doc.wikimedia.org/Wikibase/master/php/docs_topics_json.html) are also very useful for interacting with/contributing to this gem.
|
6
|
+
|
7
|
+
**The gem is currently in early development and is not ready for production usage**.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -24,7 +26,7 @@ Or install it yourself as:
|
|
24
26
|
|
25
27
|
You can view the YARD docs on GitHub Pages [here](https://connorshea.github.io/wikidatum/index.html).
|
26
28
|
|
27
|
-
Currently, the gem is able to hit a few
|
29
|
+
Currently, the gem is able to hit a few of the basic endpoints, and currently has no way to provide authentication. The additional features will be added later.
|
28
30
|
|
29
31
|
```ruby
|
30
32
|
require 'wikidatum'
|
@@ -57,6 +59,26 @@ item.label(lang: :en).value #=> "Earth"
|
|
57
59
|
|
58
60
|
# Get the values for all English aliases on this item.
|
59
61
|
item.aliases(langs: [:en]).map(&:value) #=> ["Planet Earth", "Pale Blue Dot"]
|
62
|
+
|
63
|
+
statement_id = 'Q123$4543523c-1d1d-1111-1e1e-11b11111b1f1'
|
64
|
+
statement = wikidatum_client.statement(id: statement_id) #=> Wikidatum::Statement
|
65
|
+
|
66
|
+
# Add a statement to Q193581 for P577 (publication date) that has a time value of November 16, 2004.
|
67
|
+
wikidatum_client.add_statement(
|
68
|
+
id: 'Q193581',
|
69
|
+
property: 'P577',
|
70
|
+
value: Wikidatum::DataType::Time.new(
|
71
|
+
time: '+2004-11-16T00:00:00Z',
|
72
|
+
precision: 11,
|
73
|
+
calendar_model: 'https://www.wikidata.org/entity/Q12138'
|
74
|
+
)
|
75
|
+
)
|
76
|
+
|
77
|
+
# Delete a statement and include an edit summary.
|
78
|
+
wikidatum_client.delete_statement(
|
79
|
+
id: 'Q123$4543523c-1d1d-1111-1e1e-11b11111b1f1',
|
80
|
+
comment: 'Deleting this statement because it is inaccurate.'
|
81
|
+
)
|
60
82
|
```
|
61
83
|
|
62
84
|
## Development
|
data/lib/wikidatum/client.rb
CHANGED
@@ -6,7 +6,19 @@ require 'faraday/net_http'
|
|
6
6
|
module Wikidatum
|
7
7
|
class Client
|
8
8
|
ITEM_REGEX = /^Q?\d+$/.freeze
|
9
|
+
PROPERTY_REGEX = /^P?\d+$/.freeze
|
9
10
|
STATEMENT_REGEX = /^Q?\d+\$[\w-]+$/.freeze
|
11
|
+
VALID_RANKS = ['preferred', 'normal', 'deprecated'].freeze
|
12
|
+
VALID_DATA_TYPES = [
|
13
|
+
'Wikidatum::DataType::GlobeCoordinate',
|
14
|
+
'Wikidatum::DataType::MonolingualText',
|
15
|
+
'Wikidatum::DataType::NoValue',
|
16
|
+
'Wikidatum::DataType::Quantity',
|
17
|
+
'Wikidatum::DataType::SomeValue',
|
18
|
+
'Wikidatum::DataType::Time',
|
19
|
+
'Wikidatum::DataType::WikibaseItem',
|
20
|
+
'Wikidatum::DataType::WikibaseString'
|
21
|
+
].freeze
|
10
22
|
|
11
23
|
# @return [String] the root URL of the Wikibase instance we want to interact
|
12
24
|
# with. If not provided, will default to Wikidata.
|
@@ -20,31 +32,41 @@ module Wikidatum
|
|
20
32
|
# Wikibase API.
|
21
33
|
attr_reader :user_agent
|
22
34
|
|
35
|
+
# @return [Boolean] whether this client should allow non-GET requests if
|
36
|
+
# authentication hasn't been provided. Defaults to false.
|
37
|
+
attr_reader :allow_ip_edits
|
38
|
+
|
23
39
|
# Create a new Wikidatum::Client to interact with the Wikibase REST API.
|
24
40
|
#
|
25
41
|
# @example
|
26
42
|
# wikidatum_client = Wikidatum::Client.new(
|
27
|
-
# user_agent: '
|
43
|
+
# user_agent: 'Bot Name',
|
28
44
|
# wikibase_url: 'https://www.wikidata.org',
|
29
45
|
# bot: true
|
30
46
|
# )
|
31
47
|
#
|
32
48
|
# @param user_agent [String] The UserAgent header to send with all requests
|
33
|
-
# to the Wikibase API.
|
49
|
+
# to the Wikibase API. This will be prepended with the string "Wikidatum
|
50
|
+
# Ruby gem vX.X.X:".
|
34
51
|
# @param wikibase_url [String] The root URL of the Wikibase instance we want
|
35
52
|
# to interact with. If not provided, will default to
|
36
53
|
# `https://www.wikidata.org`. Do not include a `/` at the end of the URL.
|
37
54
|
# @param bot [Boolean] Whether requests sent by this client instance should
|
38
55
|
# be registered as bot requests. Defaults to `true`.
|
56
|
+
# @param allow_ip_edits [Boolean] whether this client should allow non-GET
|
57
|
+
# requests if authentication hasn't been provided. Defaults to false. If
|
58
|
+
# this is set to true, the IP address of the device from which the
|
59
|
+
# request was sent will be credited for the edit. Make sure not to allow
|
60
|
+
# these edits if you don't want your IP address (and in many cases, a
|
61
|
+
# very close approximation of your physical location) exposed publicly.
|
39
62
|
# @return [Wikidatum::Client]
|
40
|
-
def initialize(user_agent:, wikibase_url: 'https://www.wikidata.org', bot: true)
|
63
|
+
def initialize(user_agent:, wikibase_url: 'https://www.wikidata.org', bot: true, allow_ip_edits: false)
|
41
64
|
raise ArgumentError, "Wikibase URL must not end with a `/`, got #{wikibase_url.inspect}." if wikibase_url.end_with?('/')
|
42
65
|
|
43
|
-
|
44
|
-
# restrict the ability for end-users to actually set the UserAgent?
|
45
|
-
@user_agent = user_agent
|
66
|
+
@user_agent = "Wikidatum Ruby gem v#{Wikidatum::VERSION}: #{user_agent}"
|
46
67
|
@wikibase_url = wikibase_url
|
47
68
|
@bot = bot
|
69
|
+
@allow_ip_edits = allow_ip_edits
|
48
70
|
|
49
71
|
Faraday.default_adapter = :net_http
|
50
72
|
end
|
@@ -97,7 +119,7 @@ module Wikidatum
|
|
97
119
|
# wikidatum_client.add_statement(
|
98
120
|
# id: 'Q123',
|
99
121
|
# property: 'P23',
|
100
|
-
#
|
122
|
+
# value: Wikidatum::DataType::WikibaseString.new(string: 'Foo'),
|
101
123
|
# comment: 'Adding something or another.'
|
102
124
|
# )
|
103
125
|
#
|
@@ -105,7 +127,7 @@ module Wikidatum
|
|
105
127
|
# wikidatum_client.add_statement(
|
106
128
|
# id: 'Q123',
|
107
129
|
# property: 'P124',
|
108
|
-
#
|
130
|
+
# value: Wikidatum::DataType::NoValue.new(
|
109
131
|
# type: :no_value,
|
110
132
|
# value: nil
|
111
133
|
# )
|
@@ -115,7 +137,7 @@ module Wikidatum
|
|
115
137
|
# wikidatum_client.add_statement(
|
116
138
|
# id: 'Q123',
|
117
139
|
# property: 'P124',
|
118
|
-
#
|
140
|
+
# value: Wikidatum::DataType::SomeValue.new(
|
119
141
|
# type: :some_value,
|
120
142
|
# value: nil
|
121
143
|
# )
|
@@ -125,7 +147,7 @@ module Wikidatum
|
|
125
147
|
# wikidatum_client.add_statement(
|
126
148
|
# id: 'Q123',
|
127
149
|
# property: 'P124',
|
128
|
-
#
|
150
|
+
# value: Wikidatum::DataType::GlobeCoordinate.new(
|
129
151
|
# latitude: 52.51666,
|
130
152
|
# longitude: 13.3833,
|
131
153
|
# precision: 0.01666,
|
@@ -137,7 +159,7 @@ module Wikidatum
|
|
137
159
|
# wikidatum_client.add_statement(
|
138
160
|
# id: 'Q123',
|
139
161
|
# property: 'P124',
|
140
|
-
#
|
162
|
+
# value: Wikidatum::DataType::MonolingualText.new(
|
141
163
|
# language: 'en',
|
142
164
|
# text: 'Foobar'
|
143
165
|
# )
|
@@ -147,10 +169,8 @@ module Wikidatum
|
|
147
169
|
# wikidatum_client.add_statement(
|
148
170
|
# id: 'Q123',
|
149
171
|
# property: 'P124',
|
150
|
-
#
|
172
|
+
# value: Wikidatum::DataType::Quantity.new(
|
151
173
|
# amount: '+12',
|
152
|
-
# upper_bound: nil,
|
153
|
-
# lower_bound: nil,
|
154
174
|
# unit: 'https://wikidata.org/entity/Q1234'
|
155
175
|
# )
|
156
176
|
# )
|
@@ -159,9 +179,8 @@ module Wikidatum
|
|
159
179
|
# wikidatum_client.add_statement(
|
160
180
|
# id: 'Q123',
|
161
181
|
# property: 'P124',
|
162
|
-
#
|
182
|
+
# value: Wikidatum::DataType::Time.new(
|
163
183
|
# time: '+2022-08-12T00:00:00Z',
|
164
|
-
# time_zone: 0,
|
165
184
|
# precision: 11,
|
166
185
|
# calendar_model: 'https://wikidata.org/entity/Q1234'
|
167
186
|
# )
|
@@ -171,66 +190,70 @@ module Wikidatum
|
|
171
190
|
# wikidatum_client.add_statement(
|
172
191
|
# id: 'Q123',
|
173
192
|
# property: 'P124',
|
174
|
-
#
|
175
|
-
# entity_type: 'item',
|
176
|
-
# numeric_id: 1234,
|
193
|
+
# value: Wikidatum::DataType::WikibaseItem.new(
|
177
194
|
# id: 'Q1234'
|
178
195
|
# )
|
179
196
|
# )
|
180
197
|
#
|
181
|
-
# @param id [String] the ID of the item on which the statement will be added.
|
182
|
-
# @param property [String] property ID in the format 'P123'.
|
183
|
-
# @param
|
184
|
-
# @param
|
185
|
-
# @param qualifiers [Hash<String, Array<Wikidatum::Snak>>]
|
198
|
+
# @param id [String, Integer] the ID of the item on which the statement will be added.
|
199
|
+
# @param property [String, Integer] property ID in the format 'P123', or an integer.
|
200
|
+
# @param value [Wikidatum::DataType::GlobeCoordinate, Wikidatum::DataType::MonolingualText, Wikidatum::DataType::Quantity, Wikidatum::DataType::WikibaseString, Wikidatum::DataType::Time, Wikidatum::DataType::WikibaseItem, Wikidatum::DataType::NoValue, Wikidatum::DataType::SomeValue] the value of the statement being created.
|
201
|
+
# @param qualifiers [Array<Wikidatum::Qualifier>]
|
186
202
|
# @param references [Array<Wikidatum::Reference>]
|
187
|
-
# @param rank [String]
|
203
|
+
# @param rank [String, Symbol] Valid ranks are 'preferred', 'normal', or
|
204
|
+
# 'deprecated'. Defaults to 'normal'. Also accepts Symbol for these ranks.
|
188
205
|
# @param tags [Array<String>]
|
189
206
|
# @param comment [String, nil]
|
190
207
|
# @return [Boolean] True if the request succeeded.
|
191
|
-
def add_statement(id:, property:,
|
208
|
+
def add_statement(id:, property:, value:, qualifiers: [], references: [], rank: 'normal', tags: [], comment: nil)
|
192
209
|
raise ArgumentError, "#{id.inspect} is an invalid Wikibase QID. Must be an integer, a string representation of an integer, or in the format 'Q123'." unless id.is_a?(Integer) || id.match?(ITEM_REGEX)
|
210
|
+
raise ArgumentError, "#{property.inspect} is an invalid Wikibase PID. Must be an integer, a string representation of an integer, or in the format 'P123'." unless property.is_a?(Integer) || property.match?(PROPERTY_REGEX)
|
211
|
+
raise ArgumentError, "#{rank.inspect} is an invalid rank. Must be normal, preferred, or deprecated." unless VALID_RANKS.include?(rank.to_s)
|
212
|
+
raise ArgumentError, "Expected an instance of one of Wikidatum::DataType's subclasses for value, but got #{value.inspect}." unless VALID_DATA_TYPES.include?(value.class.to_s)
|
193
213
|
|
194
214
|
id = coerce_item_id(id)
|
215
|
+
property = coerce_property_id(property)
|
195
216
|
|
196
|
-
|
197
|
-
|
198
|
-
datatype ||= datavalue.wikibase_datatype
|
199
|
-
|
200
|
-
case datavalue.class.to_s
|
201
|
-
when 'Wikidatum::DataValueType::NoValue'
|
217
|
+
case value.class.to_s
|
218
|
+
when 'Wikidatum::DataType::NoValue'
|
202
219
|
statement_hash = {
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
220
|
+
property: {
|
221
|
+
id: property
|
222
|
+
},
|
223
|
+
value: {
|
224
|
+
type: 'novalue'
|
207
225
|
}
|
208
226
|
}
|
209
|
-
when 'Wikidatum::
|
227
|
+
when 'Wikidatum::DataType::SomeValue'
|
210
228
|
statement_hash = {
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
229
|
+
property: {
|
230
|
+
id: property
|
231
|
+
},
|
232
|
+
value: {
|
233
|
+
type: 'somevalue'
|
215
234
|
}
|
216
235
|
}
|
217
|
-
when 'Wikidatum::
|
236
|
+
when 'Wikidatum::DataType::GlobeCoordinate', 'Wikidatum::DataType::MonolingualText', 'Wikidatum::DataType::Quantity', 'Wikidatum::DataType::WikibaseString', 'Wikidatum::DataType::Time', 'Wikidatum::DataType::WikibaseItem'
|
218
237
|
statement_hash = {
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
value: datavalue.marshal_dump
|
226
|
-
}
|
238
|
+
property: {
|
239
|
+
id: property
|
240
|
+
},
|
241
|
+
value: {
|
242
|
+
type: 'value',
|
243
|
+
content: value.marshal_dump
|
227
244
|
}
|
228
245
|
}
|
229
|
-
else
|
230
|
-
raise ArgumentError, "Expected an instance of one of Wikidatum::DataValueType's subclasses for datavalue, but got #{datavalue.inspect}."
|
231
246
|
end
|
232
247
|
|
233
|
-
body = {
|
248
|
+
body = {
|
249
|
+
statement: statement_hash.merge(
|
250
|
+
{
|
251
|
+
qualifiers: qualifiers,
|
252
|
+
references: references,
|
253
|
+
rank: rank.to_s
|
254
|
+
}
|
255
|
+
)
|
256
|
+
}
|
234
257
|
|
235
258
|
response = post_request("/entities/items/#{id}/statements", body, tags: tags, comment: comment)
|
236
259
|
|
@@ -261,6 +284,29 @@ module Wikidatum
|
|
261
284
|
response.success?
|
262
285
|
end
|
263
286
|
|
287
|
+
# Is the current instance of Client authenticated as a Wikibase user?
|
288
|
+
#
|
289
|
+
# @return [Boolean]
|
290
|
+
def authenticated?
|
291
|
+
# TODO: Make it possible for this to be true once authentication
|
292
|
+
# is implemented.
|
293
|
+
false
|
294
|
+
end
|
295
|
+
|
296
|
+
# Does the current instance of Client allow anonymous IP-based edits?
|
297
|
+
#
|
298
|
+
# @return [Boolean]
|
299
|
+
def allow_ip_edits?
|
300
|
+
@allow_ip_edits
|
301
|
+
end
|
302
|
+
|
303
|
+
# Is the current instance of Client editing as a bot?
|
304
|
+
#
|
305
|
+
# @return [Boolean]
|
306
|
+
def bot?
|
307
|
+
@bot
|
308
|
+
end
|
309
|
+
|
264
310
|
private
|
265
311
|
|
266
312
|
# For now this just returns the `@wikibase_url`, but in the future the API
|
@@ -309,7 +355,9 @@ module Wikidatum
|
|
309
355
|
# @param tags [Array<String>] The tags to apply to the edit being made by this request, for PUT/POST/DELETE requests.
|
310
356
|
# @param comment [String] The edit description, for PUT/POST/DELETE requests.
|
311
357
|
# @return [Hash] JSON response, parsed into a hash.
|
312
|
-
def post_request(path, body = {}, tags:
|
358
|
+
def post_request(path, body = {}, tags: [], comment: nil)
|
359
|
+
ensure_edit_permitted!
|
360
|
+
|
313
361
|
url = "#{api_url}#{path}"
|
314
362
|
|
315
363
|
body[:bot] = @bot
|
@@ -323,6 +371,13 @@ module Wikidatum
|
|
323
371
|
|
324
372
|
puts response.body.inspect if ENV['DEBUG']
|
325
373
|
|
374
|
+
# Error handling if it doesn't return a 200
|
375
|
+
unless response.success?
|
376
|
+
puts 'Something went wrong with this request!'
|
377
|
+
puts "Status Code: #{response.status}"
|
378
|
+
puts response.body.inspect
|
379
|
+
end
|
380
|
+
|
326
381
|
response
|
327
382
|
end
|
328
383
|
|
@@ -333,6 +388,8 @@ module Wikidatum
|
|
333
388
|
# @param comment [String] The edit description, for PUT/POST/DELETE requests.
|
334
389
|
# @return [Hash] JSON response, parsed into a hash.
|
335
390
|
def delete_request(path, tags: [], comment: nil)
|
391
|
+
ensure_edit_permitted!
|
392
|
+
|
336
393
|
url = "#{api_url}#{path}"
|
337
394
|
|
338
395
|
body = {}
|
@@ -368,5 +425,31 @@ module Wikidatum
|
|
368
425
|
|
369
426
|
"Q#{id}"
|
370
427
|
end
|
428
|
+
|
429
|
+
# Coerce a Property ID in the formats 'P123', '123' or 123 into a consistent
|
430
|
+
# 'P123' format. We need to have the ID in the format 'P123' for the API
|
431
|
+
# request, which is why coercion is necessary.
|
432
|
+
#
|
433
|
+
# @param property_id [String, Integer]
|
434
|
+
# @return [String]
|
435
|
+
def coerce_property_id(property_id)
|
436
|
+
return property_id if property_id.to_s.start_with?('P')
|
437
|
+
|
438
|
+
"P#{property_id}"
|
439
|
+
end
|
440
|
+
|
441
|
+
# Check if authentication has been provided, and then check if IP edits
|
442
|
+
# are allowed. If neither condition returns true, raise an error.
|
443
|
+
#
|
444
|
+
# Also check if the user is performing IP edits as a bot, which will
|
445
|
+
# always return a 403 error from the REST API, and return a specific
|
446
|
+
# error message if so.
|
447
|
+
#
|
448
|
+
# @return [void]
|
449
|
+
# @raise [DisallowedIpEditError, DisallowedBotEditError]
|
450
|
+
def ensure_edit_permitted!
|
451
|
+
raise DisallowedIpEditError if !authenticated? && !allow_ip_edits?
|
452
|
+
raise DisallowedBotEditError if !authenticated? && bot?
|
453
|
+
end
|
371
454
|
end
|
372
455
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# For more information on the possible types that can be returned by
|
4
|
+
# datavalues, see the official documentation:
|
5
|
+
# https://doc.wikimedia.org/Wikibase/master/php/md_docs_topics_json.html#json_datavalues
|
6
|
+
module Wikidatum::DataType
|
7
|
+
class Base
|
8
|
+
# Represents the type for this instance.
|
9
|
+
#
|
10
|
+
# Possible values for the `type` attribute are:
|
11
|
+
#
|
12
|
+
# - `:no_value`: No value
|
13
|
+
# - `:some_value`: Unknown value
|
14
|
+
# - `:globe_coordinate`: {DataType::GlobeCoordinate}
|
15
|
+
# - `:monolingual_text`: {DataType::MonolingualText}
|
16
|
+
# - `:quantity`: {DataType::Quantity}
|
17
|
+
# - `:string`: {DataType::WikibaseString}
|
18
|
+
# - `:time`: {DataType::Time}
|
19
|
+
# - `:wikibase_item`: {DataType::WikibaseItem}
|
20
|
+
#
|
21
|
+
# @return [Symbol]
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# The value of the "content" attribute in the response.
|
25
|
+
#
|
26
|
+
# If the `type` is `novalue` or `somevalue`, this returns `nil`.
|
27
|
+
#
|
28
|
+
# @return [DataType::GlobeCoordinate, DataType::MonolingualText, DataType::Quantity, DataType::WikibaseString, DataType::Time, DataType::WikibaseItem, nil]
|
29
|
+
attr_reader :content
|
30
|
+
|
31
|
+
# @param type [Symbol]
|
32
|
+
# @param content [DataType::GlobeCoordinate, DataType::MonolingualText, DataType::Quantity, DataType::WikibaseString, DataType::Time, DataType::WikibaseItem, nil] nil if type is no_value or some_value
|
33
|
+
# @return [void]
|
34
|
+
def initialize(type:, content:)
|
35
|
+
@type = type
|
36
|
+
@content = content
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Hash]
|
40
|
+
def to_h
|
41
|
+
{
|
42
|
+
type: @type,
|
43
|
+
content: @content&.to_h
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# @!visibility private
|
48
|
+
#
|
49
|
+
# @param data_type [String] The value of `data-type` for the given Statement or Qualifier's property.
|
50
|
+
# @param data_value_json [Hash] The `content` part of value object.
|
51
|
+
# @return [Wikidatum::DataType::Base] An instance of Base.
|
52
|
+
def self.marshal_load(data_type, data_value_json)
|
53
|
+
unless Wikidatum::DataType::DATA_TYPES.keys.include?(data_type.to_sym)
|
54
|
+
puts "WARNING: Unsupported data type (#{data_type})"
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
Object.const_get(Wikidatum::DataType::DATA_TYPES[data_type.to_sym]).marshal_load(data_value_json)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,23 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'wikidatum/
|
3
|
+
require 'wikidatum/data_type/base'
|
4
4
|
|
5
|
-
# The Globe Coordinate type
|
5
|
+
# The Globe Coordinate type JSON looks like this:
|
6
6
|
#
|
7
7
|
# ```json
|
8
8
|
# {
|
9
|
-
# "
|
10
|
-
# "
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
9
|
+
# "property": {
|
10
|
+
# "id": "P740",
|
11
|
+
# "data-type": "globe-coordinate"
|
12
|
+
# },
|
13
|
+
# "value": {
|
14
|
+
# "type": "value",
|
15
|
+
# "content": {
|
16
|
+
# "latitude": 38.8977,
|
17
|
+
# "longitude": -77.0365,
|
18
|
+
# "precision": 0.0001,
|
14
19
|
# "globe": "http://www.wikidata.org/entity/Q2"
|
15
|
-
# }
|
16
|
-
# "type": "globecoordinate"
|
20
|
+
# }
|
17
21
|
# }
|
18
22
|
# }
|
19
23
|
# ```
|
20
|
-
class Wikidatum::
|
24
|
+
class Wikidatum::DataType::GlobeCoordinate
|
21
25
|
# @return [Float]
|
22
26
|
attr_reader :latitude
|
23
27
|
|
@@ -56,22 +60,19 @@ class Wikidatum::DataValueType::GlobeCoordinate
|
|
56
60
|
#
|
57
61
|
# @return [String]
|
58
62
|
def wikibase_type
|
59
|
-
'
|
63
|
+
'globe-coordinate'
|
60
64
|
end
|
61
65
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
# @return [String]
|
66
|
-
def wikibase_datatype
|
67
|
-
'globe-coordinate' # yes, really
|
66
|
+
# @return [Symbol]
|
67
|
+
def self.symbolized_name
|
68
|
+
:monolingual_text
|
68
69
|
end
|
69
70
|
|
70
71
|
# @!visibility private
|
71
72
|
def self.marshal_load(data_value_json)
|
72
|
-
Wikidatum::
|
73
|
-
type:
|
74
|
-
|
73
|
+
Wikidatum::DataType::Base.new(
|
74
|
+
type: symbolized_name,
|
75
|
+
content: new(
|
75
76
|
latitude: data_value_json['latitude'],
|
76
77
|
longitude: data_value_json['longitude'],
|
77
78
|
precision: data_value_json['precision'],
|
@@ -1,21 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'wikidatum/
|
3
|
+
require 'wikidatum/data_type/base'
|
4
4
|
|
5
|
-
# The Monolingual Text type
|
5
|
+
# The Monolingual Text type JSON looks like this:
|
6
6
|
#
|
7
7
|
# ```json
|
8
8
|
# {
|
9
|
-
# "
|
10
|
-
# "
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# "type": "
|
9
|
+
# "property": {
|
10
|
+
# "id": "P13432",
|
11
|
+
# "data-type": "monolingualtext"
|
12
|
+
# },
|
13
|
+
# "value": {
|
14
|
+
# "type": "value",
|
15
|
+
# "content": {
|
16
|
+
# "text": "foo",
|
17
|
+
# "language": "en-gb"
|
18
|
+
# }
|
15
19
|
# }
|
16
20
|
# }
|
17
21
|
# ```
|
18
|
-
class Wikidatum::
|
22
|
+
class Wikidatum::DataType::MonolingualText
|
19
23
|
# @return [String] the language code, e.g. 'en'
|
20
24
|
attr_reader :language
|
21
25
|
|
@@ -45,19 +49,16 @@ class Wikidatum::DataValueType::MonolingualText
|
|
45
49
|
'monolingualtext'
|
46
50
|
end
|
47
51
|
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
# @return [String]
|
52
|
-
def wikibase_datatype
|
53
|
-
wikibase_type
|
52
|
+
# @return [Symbol]
|
53
|
+
def self.symbolized_name
|
54
|
+
:monolingual_text
|
54
55
|
end
|
55
56
|
|
56
57
|
# @!visibility private
|
57
58
|
def self.marshal_load(data_value_json)
|
58
|
-
Wikidatum::
|
59
|
-
type:
|
60
|
-
|
59
|
+
Wikidatum::DataType::Base.new(
|
60
|
+
type: symbolized_name,
|
61
|
+
content: new(
|
61
62
|
language: data_value_json['language'],
|
62
63
|
text: data_value_json['text']
|
63
64
|
)
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'wikidatum/
|
3
|
+
require 'wikidatum/data_type/base'
|
4
4
|
|
5
5
|
# The NoValue type actually has no datavalue key in the blob at all. We work
|
6
6
|
# around this by just passing nil to the serializer.
|
7
7
|
|
8
8
|
# Represents "no value".
|
9
|
-
class Wikidatum::
|
9
|
+
class Wikidatum::DataType::NoValue < Wikidatum::DataType::Base
|
10
10
|
# The "type" value used by Wikibase, for use when creating/updating statements.
|
11
11
|
#
|
12
12
|
# @return [String]
|
@@ -14,16 +14,8 @@ class Wikidatum::DataValueType::NoValue < Wikidatum::DataValueType::Base
|
|
14
14
|
'string'
|
15
15
|
end
|
16
16
|
|
17
|
-
# The "datatype" value used by Wikibase, usually identical to wikibase_type
|
18
|
-
# but not always.
|
19
|
-
#
|
20
|
-
# @return [String]
|
21
|
-
def wikibase_datatype
|
22
|
-
wikibase_type
|
23
|
-
end
|
24
|
-
|
25
17
|
# @!visibility private
|
26
18
|
def self.marshal_load(_data_value_json)
|
27
|
-
new(type: :no_value,
|
19
|
+
new(type: :no_value, content: nil)
|
28
20
|
end
|
29
21
|
end
|