atdis 0.1 → 0.2
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.
- data/README.md +2 -2
- data/docs/ATDIS-1.0.7 Application Tracking Data Interchange Specification (v1.0).doc +0 -0
- data/docs/ATDIS-1.0.7 Application Tracking Data Interchange Specification (v1.0).pdf +0 -0
- data/lib/atdis/application.rb +62 -31
- data/lib/atdis/document.rb +7 -5
- data/lib/atdis/event.rb +12 -7
- data/lib/atdis/location.rb +13 -10
- data/lib/atdis/model.rb +148 -35
- data/lib/atdis/page.rb +45 -29
- data/lib/atdis/person.rb +6 -4
- data/lib/atdis/validators.rb +33 -6
- data/lib/atdis/version.rb +1 -1
- data/spec/atdis/application_spec.rb +166 -33
- data/spec/atdis/document_spec.rb +4 -0
- data/spec/atdis/event_spec.rb +4 -0
- data/spec/atdis/location_spec.rb +56 -5
- data/spec/atdis/model_spec.rb +136 -5
- data/spec/atdis/page_spec.rb +119 -17
- data/spec/atdis/person_spec.rb +4 -0
- metadata +24 -24
- data/docs/ATDIS-1.0.4 Application Tracking Data Interchange Specification.docx +0 -0
- data/docs/ATDIS-1.0.4 Application Tracking Data Interchange Specification.pdf +0 -0
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Atdis
|
2
2
|
|
3
|
-
[](https://travis-ci.org/openaustralia/atdis) [](https://coveralls.io/r/openaustralia/atdis?branch=master) [](https://codeclimate.com/github/openaustralia/atdis)
|
3
|
+
[](https://travis-ci.org/openaustralia/atdis) [](https://coveralls.io/r/openaustralia/atdis?branch=master) [](https://codeclimate.com/github/openaustralia/atdis) [](http://badge.fury.io/rb/atdis)
|
4
4
|
|
5
5
|
A ruby interface to the application tracking data interchange specification (ATDIS) API
|
6
6
|
|
7
|
-
We're developing this against version ATDIS 1.0.
|
7
|
+
We're developing this against version ATDIS 1.0.7.
|
8
8
|
|
9
9
|
This is **highly alpha** software that probably doesn't yet do what it says on the tin. It is very much a work in progress.
|
10
10
|
|
Binary file
|
Binary file
|
data/lib/atdis/application.rb
CHANGED
@@ -2,41 +2,72 @@ require 'multi_json'
|
|
2
2
|
|
3
3
|
module ATDIS
|
4
4
|
class Application < Model
|
5
|
-
field_mappings
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
5
|
+
# TODO When we remove support for Ruby 1.8 we can convert field_mappings back to a hash
|
6
|
+
# which is much more readable
|
7
|
+
set_field_mappings [
|
8
|
+
[:application, [
|
9
|
+
[:info, [
|
10
|
+
[:dat_id, [:dat_id, String, {:level => 1}]],
|
11
|
+
[:last_modified_date, [:last_modified_date, DateTime, {:level => 1}]],
|
12
|
+
[:description, [:description, String, {:level => 1}]],
|
13
|
+
[:authority, [:authority, String, {:level => 1}]],
|
14
|
+
[:lodgement_date, [:lodgement_date, DateTime, {:level => 1}]],
|
15
|
+
[:determination_date, [:determination_date, DateTime, {:level => 1}]],
|
16
|
+
[:status, [:status, String, {:level => 1}]],
|
17
|
+
[:notification_start_date, [:notification_start_date, DateTime, {:level => 1}]],
|
18
|
+
[:notification_end_date, [:notification_end_date, DateTime, {:level => 1}]],
|
19
|
+
[:officer, [:officer, String, {:level => 1}]],
|
20
|
+
[:estimated_cost, [:estimated_cost, String, {:level => 1}]]
|
21
|
+
]],
|
22
|
+
[:reference, [
|
23
|
+
[:more_info_url, [:more_info_url, URI, {:level => 1}]],
|
24
|
+
[:comments_url, [:comments_url, URI, {:level => 1}]]
|
25
|
+
]],
|
26
|
+
[:location, [:location, Location, {:level => 1}]],
|
27
|
+
[:events, [:events, Event, {:level => 1}]],
|
28
|
+
[:documents, [:documents, Document, {:level => 1}]],
|
29
|
+
[:people, [:people, Person, {:level => 2}]],
|
30
|
+
[:extended, [:extended, Object, {:level => 3}]]
|
31
|
+
]]
|
32
|
+
]
|
33
|
+
|
30
34
|
# Mandatory parameters
|
31
|
-
validates :dat_id, :last_modified_date, :description, :authority, :lodgement_date, :determination_date, :status,
|
32
|
-
:
|
35
|
+
validates :dat_id, :last_modified_date, :description, :authority, :lodgement_date, :determination_date, :status,
|
36
|
+
:presence_before_type_cast => {:spec_section => "4.3.1"}
|
37
|
+
validates :more_info_url, :presence_before_type_cast => {:spec_section => "4.3.2"}
|
38
|
+
validates :location, :presence_before_type_cast => {:spec_section => "4.3.3"}
|
39
|
+
validates :events, :presence_before_type_cast => {:spec_section => "4.3.4"}
|
40
|
+
validates :documents, :presence_before_type_cast => {:spec_section => "4.3.5"}
|
33
41
|
|
34
42
|
# Other validations
|
35
|
-
validates :
|
36
|
-
|
37
|
-
validates :more_info_url, :http_url =>
|
38
|
-
validates :location, :valid => true
|
43
|
+
validates :last_modified_date, :lodgement_date, :date_time => {:spec_section => "4.3.8"}
|
44
|
+
validates :determination_date, :notification_start_date, :notification_end_date, :date_time_or_none => {:spec_section => "4.3.1"}
|
45
|
+
validates :more_info_url, :http_url => {:spec_section => "4.3.2"}
|
46
|
+
validates :location, :events, :documents, :people, :valid => true
|
47
|
+
validates :events, :documents, :array => {:spec_section => "4.3.4"}
|
48
|
+
# TODO people should be an array if it's included
|
49
|
+
|
50
|
+
validate :notification_dates_consistent!
|
51
|
+
|
52
|
+
def notification_dates_consistent!
|
53
|
+
if notification_start_date_before_type_cast == "none" && notification_end_date_before_type_cast != "none"
|
54
|
+
errors.add(:notification_start_date, ErrorMessage["can't be none unless notification_end_date is none as well", "4.3.1"])
|
55
|
+
end
|
56
|
+
if notification_start_date_before_type_cast != "none" && notification_end_date_before_type_cast == "none"
|
57
|
+
errors.add(:notification_end_date, ErrorMessage["can't be none unless notification_start_date is none as well", "4.3.1"])
|
58
|
+
end
|
59
|
+
if notification_start_date_before_type_cast && notification_end_date_before_type_cast.blank?
|
60
|
+
errors.add(:notification_end_date, ErrorMessage["can not be blank if notification_start_date is set", "4.3.1"])
|
61
|
+
end
|
62
|
+
if notification_start_date_before_type_cast.blank? && notification_end_date_before_type_cast
|
63
|
+
errors.add(:notification_start_date, ErrorMessage["can not be blank if notification_end_date is set", "4.3.1"])
|
64
|
+
end
|
65
|
+
if notification_start_date && notification_end_date && notification_start_date > notification_end_date
|
66
|
+
errors.add(:notification_end_date, ErrorMessage["can not be earlier than notification_start_date", "4.3.1"])
|
67
|
+
end
|
68
|
+
end
|
39
69
|
|
70
|
+
# TODO Validate contents of estimated_cost
|
40
71
|
# TODO Validate associated like locations, events, documents, people
|
41
72
|
# TODO Do we need to do extra checking to ensure that events, documents and people are arrays?
|
42
73
|
# TODO Separate validation for L2 and L3 compliance?
|
data/lib/atdis/document.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
module ATDIS
|
2
2
|
class Document < Model
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
3
|
+
set_field_mappings [
|
4
|
+
[:ref, [:ref, String, {:level => 1}]],
|
5
|
+
[:title, [:title, String, {:level => 1}]],
|
6
|
+
[:document_url, [:document_url, URI, {:level => 1}]]
|
7
|
+
]
|
6
8
|
|
7
9
|
# Mandatory parameters
|
8
|
-
validates :ref, :title, :document_url, :presence_before_type_cast =>
|
10
|
+
validates :ref, :title, :document_url, :presence_before_type_cast => {:spec_section => "4.3.5"}
|
9
11
|
# Other validations
|
10
|
-
validates :document_url, :http_url =>
|
12
|
+
validates :document_url, :http_url => {:spec_section => "4.3.5"}
|
11
13
|
end
|
12
14
|
end
|
data/lib/atdis/event.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
module ATDIS
|
2
2
|
class Event < Model
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
|
3
|
+
set_field_mappings [
|
4
|
+
[:id, [:id, String, {:level => 1}]],
|
5
|
+
[:date, [:date, DateTime, {:level => 1}]],
|
6
|
+
[:description, [:description, String, {:level => 1}]],
|
7
|
+
[:event_type, [:event_type, String, {:level => 1}]],
|
8
|
+
[:status, [:status, String, {:level => 1}]]
|
9
|
+
]
|
10
|
+
|
9
11
|
# Mandatory parameters
|
10
|
-
validates :id, :date, :description, :presence_before_type_cast =>
|
12
|
+
validates :id, :date, :description, :presence_before_type_cast => {:spec_section => "4.3.4"}
|
11
13
|
end
|
14
|
+
|
15
|
+
# TODO Check that :id is unique within an authority
|
16
|
+
|
12
17
|
end
|
data/lib/atdis/location.rb
CHANGED
@@ -2,17 +2,20 @@ require "rgeo/geo_json"
|
|
2
2
|
|
3
3
|
module ATDIS
|
4
4
|
class Location < Model
|
5
|
-
|
6
|
-
:
|
7
|
-
|
8
|
-
:
|
9
|
-
:
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
set_field_mappings [
|
6
|
+
[:address, [:address, String, {:level => 1}]],
|
7
|
+
[:land_title_ref, [
|
8
|
+
[:lot, [:lot, String, {:level => 1}]],
|
9
|
+
[:section, [:section, String, {:none_is_nil => true, :level => 1}]],
|
10
|
+
[:dpsp_id, [:dpsp_id, String, {:level => 1}]]
|
11
|
+
]],
|
12
|
+
[:geometry, [:geometry, RGeo::GeoJSON, {:level => 1}]]
|
13
|
+
]
|
13
14
|
# Mandatory parameters
|
14
|
-
validates :address, :lot, :section, :dpsp_id, :presence_before_type_cast =>
|
15
|
+
validates :address, :lot, :section, :dpsp_id, :presence_before_type_cast => {:spec_section => "4.3.3"}
|
16
|
+
|
17
|
+
validates :geometry, :geo_json => {:spec_section => "4.3.3"}
|
15
18
|
|
16
|
-
|
19
|
+
# TODO: Provide warning if dpsp_id doesn't start with "DP" or "SP"
|
17
20
|
end
|
18
21
|
end
|
data/lib/atdis/model.rb
CHANGED
@@ -7,30 +7,39 @@ module ATDIS
|
|
7
7
|
|
8
8
|
included do
|
9
9
|
class_attribute :attribute_types
|
10
|
-
class_attribute :
|
10
|
+
class_attribute :field_mappings
|
11
11
|
end
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
+
# of the form {:section=>[String, {:none_is_nil=>true}], :address=>[String]}
|
14
15
|
def casting_attributes(p)
|
15
16
|
define_attribute_methods(p.keys.map{|k| k.to_s})
|
16
17
|
self.attribute_types = p
|
17
18
|
end
|
18
19
|
|
19
|
-
def
|
20
|
+
def set_field_mappings(p)
|
20
21
|
a, b = translate_field_mappings(p)
|
21
|
-
|
22
|
+
# field_mappings is of the form {:pagination=>{:previous=>:previous_page_no, :pages=>:total_no_pages}}
|
23
|
+
self.field_mappings = a
|
22
24
|
casting_attributes(b)
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
28
|
+
|
29
|
+
def leaf_array?(v)
|
30
|
+
if !v.kind_of?(Array)
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
v.all?{|a| !a.kind_of?(Array)}
|
34
|
+
end
|
26
35
|
|
27
36
|
def translate_field_mappings(p)
|
28
|
-
f =
|
29
|
-
ca =
|
37
|
+
f = ActiveSupport::OrderedHash.new
|
38
|
+
ca = ActiveSupport::OrderedHash.new
|
30
39
|
p.each do |k,v|
|
31
|
-
if
|
40
|
+
if leaf_array?(v)
|
32
41
|
f[k] = v[0]
|
33
|
-
ca[v.first] = v[1]
|
42
|
+
ca[v.first] = v[1..-1]
|
34
43
|
else
|
35
44
|
f2, ca2 = translate_field_mappings(v)
|
36
45
|
f[k] = f2
|
@@ -42,6 +51,17 @@ module ATDIS
|
|
42
51
|
end
|
43
52
|
end
|
44
53
|
|
54
|
+
ErrorMessage = Struct.new :message, :spec_section do
|
55
|
+
def empty?
|
56
|
+
message.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Make this behave pretty much like a string
|
60
|
+
def to_s
|
61
|
+
message
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
45
65
|
class Model
|
46
66
|
include ActiveModel::Validations
|
47
67
|
include Validators
|
@@ -50,17 +70,128 @@ module ATDIS
|
|
50
70
|
attribute_method_suffix '_before_type_cast'
|
51
71
|
attribute_method_suffix '='
|
52
72
|
|
53
|
-
attr_reader :attributes
|
73
|
+
attr_reader :attributes, :attributes_before_type_cast
|
54
74
|
# Stores any part of the json that could not be interpreted. Usually
|
55
75
|
# signals an error if it isn't empty.
|
56
|
-
attr_accessor :json_left_overs
|
76
|
+
attr_accessor :json_left_overs, :json_load_error
|
57
77
|
|
58
78
|
validate :json_left_overs_is_empty
|
59
79
|
|
80
|
+
def self.level_attribute_names(level)
|
81
|
+
attribute_types.find_all{|k,v| (v[1] || {})[:level] == level }.map{|k,v| k.to_s}
|
82
|
+
end
|
83
|
+
|
84
|
+
def json_attribute(a, new_value, mappings = field_mappings)
|
85
|
+
mappings.each do |attribute, v|
|
86
|
+
if v == a
|
87
|
+
return {attribute => new_value}
|
88
|
+
end
|
89
|
+
if v.kind_of?(Hash)
|
90
|
+
r = json_attribute(a, new_value, v)
|
91
|
+
if r
|
92
|
+
return {attribute => r}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.map_field(key, data, mappings)
|
100
|
+
mappings.each do |k, v|
|
101
|
+
if v == key
|
102
|
+
return data[k]
|
103
|
+
elsif v.kind_of?(Hash) && data.has_key?(k)
|
104
|
+
r = map_field(key, data[k], mappings[k])
|
105
|
+
if r
|
106
|
+
return r
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.unused_data(data, mappings = field_mappings)
|
114
|
+
json_left_overs = {}
|
115
|
+
data.each_key do |key|
|
116
|
+
if mappings[key]
|
117
|
+
if mappings[key].kind_of?(Hash)
|
118
|
+
l2 = unused_data(data[key], mappings[key])
|
119
|
+
json_left_overs[key] = l2 unless l2.empty?
|
120
|
+
end
|
121
|
+
else
|
122
|
+
json_left_overs[key] = data[key]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
json_left_overs
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.attribute_names_from_mappings(mappings)
|
129
|
+
result = []
|
130
|
+
mappings.each do |k, v|
|
131
|
+
if v.kind_of?(Hash)
|
132
|
+
result += attribute_names_from_mappings(v)
|
133
|
+
else
|
134
|
+
result << v
|
135
|
+
end
|
136
|
+
end
|
137
|
+
result
|
138
|
+
end
|
139
|
+
|
140
|
+
# Map json structure to our values
|
141
|
+
def self.map_fields(data, mappings = field_mappings)
|
142
|
+
values = {}
|
143
|
+
attribute_names_from_mappings(mappings).each do |attribute|
|
144
|
+
values[attribute] = map_field(attribute, data, mappings)
|
145
|
+
end
|
146
|
+
values
|
147
|
+
end
|
148
|
+
|
149
|
+
def json_errors
|
150
|
+
r = []
|
151
|
+
errors.messages.each do |attribute, e|
|
152
|
+
value = attributes[attribute.to_s]
|
153
|
+
if (value.respond_to?(:valid?) && !value.valid?)
|
154
|
+
r += value.json_errors.map{|a, b| [json_attribute(attribute, a), b]}
|
155
|
+
elsif (value && !value.respond_to?(:valid?) && value.respond_to?(:all?) && !value.all?{|v| v.valid?})
|
156
|
+
f = value.find{|v| !v.valid?}
|
157
|
+
r += f.json_errors.map{|a, b| [json_attribute(attribute, a), b]}
|
158
|
+
else
|
159
|
+
r << [json_attribute(attribute, attributes_before_type_cast[attribute.to_s]), e]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
r
|
163
|
+
end
|
164
|
+
|
165
|
+
# TODO This is doing a similar stepping down into the children that json_errors is doing. Would be nice
|
166
|
+
# to extract the commond code to make this less horrible and arbitrary
|
167
|
+
def level_used_in_children?(level)
|
168
|
+
attributes.each_value do |a|
|
169
|
+
if a.respond_to?(:level_used?) && a.level_used?(level)
|
170
|
+
return true
|
171
|
+
elsif a.kind_of?(Array) && a.any?{|b| b.level_used?(level)}
|
172
|
+
return true
|
173
|
+
end
|
174
|
+
end
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
# Have we tried to use this attribute?
|
179
|
+
def used_attribute?(a)
|
180
|
+
!attributes_before_type_cast[a].nil?
|
181
|
+
end
|
182
|
+
|
183
|
+
def level_used_locally?(level)
|
184
|
+
self.class.level_attribute_names(level).any?{|a| used_attribute?(a)}
|
185
|
+
end
|
186
|
+
|
187
|
+
def level_used?(level)
|
188
|
+
level_used_locally?(level) || level_used_in_children?(level)
|
189
|
+
end
|
190
|
+
|
60
191
|
def json_left_overs_is_empty
|
61
192
|
if json_left_overs && !json_left_overs.empty?
|
62
193
|
# We have extra parameters that shouldn't be there
|
63
|
-
errors.add(:json, "Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}")
|
194
|
+
errors.add(:json, ErrorMessage["Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}", "4"])
|
64
195
|
end
|
65
196
|
end
|
66
197
|
|
@@ -77,36 +208,18 @@ module ATDIS
|
|
77
208
|
end
|
78
209
|
|
79
210
|
def self.interpret(*params)
|
80
|
-
new(map_fields(
|
81
|
-
end
|
82
|
-
|
83
|
-
# Map json structure to our values
|
84
|
-
def self.map_fields(valid_fields, data)
|
85
|
-
values = {:json_left_overs => {}}
|
86
|
-
data.each_key do |key|
|
87
|
-
if valid_fields[key]
|
88
|
-
if valid_fields[key].kind_of?(Hash)
|
89
|
-
v2 = map_fields(valid_fields[key], data[key])
|
90
|
-
l2 = v2.delete(:json_left_overs)
|
91
|
-
values = values.merge(v2)
|
92
|
-
values[:json_left_overs][key] = l2 unless l2.empty?
|
93
|
-
else
|
94
|
-
values[valid_fields[key]] = data[key]
|
95
|
-
end
|
96
|
-
else
|
97
|
-
values[:json_left_overs][key] = data[key]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
values
|
211
|
+
new(map_fields(*params).merge(:json_left_overs => unused_data(*params)))
|
101
212
|
end
|
102
213
|
|
103
|
-
def self.cast(value, type)
|
214
|
+
def self.cast(value, type, options = {})
|
215
|
+
if options[:none_is_nil] && value == "none"
|
216
|
+
nil
|
104
217
|
# If it's already the correct type then we don't need to do anything
|
105
|
-
|
218
|
+
elsif value.kind_of?(type)
|
106
219
|
value
|
107
220
|
# Special handling for arrays. When we typecast arrays we actually typecast each member of the array
|
108
221
|
elsif value.kind_of?(Array)
|
109
|
-
value.map {|v| cast(v, type)}
|
222
|
+
value.map {|v| cast(v, type, options)}
|
110
223
|
elsif type == DateTime
|
111
224
|
cast_datetime(value)
|
112
225
|
elsif type == URI
|
@@ -137,7 +250,7 @@ module ATDIS
|
|
137
250
|
|
138
251
|
def attribute=(attr, value)
|
139
252
|
@attributes_before_type_cast[attr] = value
|
140
|
-
@attributes[attr] = Model.cast(value, attribute_types[attr.to_sym])
|
253
|
+
@attributes[attr] = Model.cast(value, attribute_types[attr.to_sym][0], attribute_types[attr.to_sym][1] || {})
|
141
254
|
end
|
142
255
|
|
143
256
|
def self.cast_datetime(value)
|
data/lib/atdis/page.rb
CHANGED
@@ -2,39 +2,48 @@ module ATDIS
|
|
2
2
|
class Page < Model
|
3
3
|
attr_accessor :url
|
4
4
|
|
5
|
-
|
6
|
-
:
|
7
|
-
:
|
8
|
-
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
|
5
|
+
set_field_mappings [
|
6
|
+
[:response, [:results, Application, {:level => 1}]],
|
7
|
+
[:count, [:count, Fixnum, {:level => 2}]],
|
8
|
+
[:pagination, [
|
9
|
+
[:previous, [:previous_page_no, Fixnum, {:level => 2}]],
|
10
|
+
[:next, [:next_page_no, Fixnum, {:level => 2}]],
|
11
|
+
[:current, [:current_page_no, Fixnum, {:level => 2}]],
|
12
|
+
[:per_page, [:no_results_per_page, Fixnum, {:level => 2}]],
|
13
|
+
[:count, [:total_no_results, Fixnum, {:level => 2}]],
|
14
|
+
[:pages, [:total_no_pages, Fixnum, {:level => 2}]]
|
15
|
+
]]
|
16
|
+
]
|
15
17
|
|
16
18
|
# Mandatory parameters
|
17
|
-
validates :results, :presence_before_type_cast =>
|
19
|
+
validates :results, :presence_before_type_cast => {:spec_section => "4.3"}
|
18
20
|
validates :results, :valid => true
|
19
21
|
validate :count_is_consistent, :all_pagination_is_present, :previous_page_no_is_consistent, :next_page_no_is_consistent
|
20
22
|
validate :current_page_no_is_consistent, :total_no_results_is_consistent
|
23
|
+
validate :json_loaded_correctly!
|
24
|
+
|
25
|
+
def json_loaded_correctly!
|
26
|
+
if json_load_error
|
27
|
+
errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
|
28
|
+
end
|
29
|
+
end
|
21
30
|
|
22
31
|
# If some of the pagination fields are present all of the required ones should be present
|
23
32
|
def all_pagination_is_present
|
24
33
|
if count || previous_page_no || next_page_no || current_page_no || no_results_per_page ||
|
25
34
|
total_no_results || total_no_pages
|
26
|
-
errors.add(:count, "should be present if pagination is being used") if count.nil?
|
27
|
-
errors.add(:current_page_no, "should be present if pagination is being used") if current_page_no.nil?
|
28
|
-
errors.add(:no_results_per_page, "should be present if pagination is being used") if no_results_per_page.nil?
|
29
|
-
errors.add(:total_no_results, "should be present if pagination is being used") if total_no_results.nil?
|
30
|
-
errors.add(:total_no_pages, "should be present if pagination is being used") if total_no_pages.nil?
|
35
|
+
errors.add(:count, ErrorMessage["should be present if pagination is being used", "6.5"]) if count.nil?
|
36
|
+
errors.add(:current_page_no, ErrorMessage["should be present if pagination is being used", "6.5"]) if current_page_no.nil?
|
37
|
+
errors.add(:no_results_per_page, ErrorMessage["should be present if pagination is being used", "6.5"]) if no_results_per_page.nil?
|
38
|
+
errors.add(:total_no_results, ErrorMessage["should be present if pagination is being used", "6.5"]) if total_no_results.nil?
|
39
|
+
errors.add(:total_no_pages, ErrorMessage["should be present if pagination is being used", "6.5"]) if total_no_pages.nil?
|
31
40
|
end
|
32
41
|
end
|
33
42
|
|
34
43
|
def count_is_consistent
|
35
44
|
if count
|
36
|
-
errors.add(:count, "is not the same as the number of applications returned") if count != results.count
|
37
|
-
errors.add(:count, "should not be larger than the number of results per page") if count > no_results_per_page
|
45
|
+
errors.add(:count, ErrorMessage["is not the same as the number of applications returned", "6.5"]) if count != results.count
|
46
|
+
errors.add(:count, ErrorMessage["should not be larger than the number of results per page", "6.5"]) if count > no_results_per_page
|
38
47
|
end
|
39
48
|
end
|
40
49
|
|
@@ -42,14 +51,14 @@ module ATDIS
|
|
42
51
|
if current_page_no
|
43
52
|
if previous_page_no
|
44
53
|
if previous_page_no != current_page_no - 1
|
45
|
-
errors.add(:previous_page_no, "should be one less than current page number or null if first page")
|
54
|
+
errors.add(:previous_page_no, ErrorMessage["should be one less than current page number or null if first page", "6.5"])
|
46
55
|
end
|
47
56
|
if current_page_no == 1
|
48
|
-
errors.add(:previous_page_no, "should be null if on the first page")
|
57
|
+
errors.add(:previous_page_no, ErrorMessage["should be null if on the first page", "6.5"])
|
49
58
|
end
|
50
59
|
else
|
51
60
|
if current_page_no > 1
|
52
|
-
errors.add(:previous_page_no, "can't be null if not on the first page")
|
61
|
+
errors.add(:previous_page_no, ErrorMessage["can't be null if not on the first page", "6.5"])
|
53
62
|
end
|
54
63
|
end
|
55
64
|
end
|
@@ -57,29 +66,29 @@ module ATDIS
|
|
57
66
|
|
58
67
|
def next_page_no_is_consistent
|
59
68
|
if next_page_no && next_page_no != current_page_no + 1
|
60
|
-
errors.add(:next_page_no, "should be one greater than current page number or null if last page")
|
69
|
+
errors.add(:next_page_no, ErrorMessage["should be one greater than current page number or null if last page", "6.5"])
|
61
70
|
end
|
62
71
|
if next_page_no.nil? && current_page_no != total_no_pages
|
63
|
-
errors.add(:next_page_no, "can't be null if not on the last page")
|
72
|
+
errors.add(:next_page_no, ErrorMessage["can't be null if not on the last page", "6.5"])
|
64
73
|
end
|
65
74
|
if next_page_no && current_page_no == total_no_pages
|
66
|
-
errors.add(:next_page_no, "should be null if on the last page")
|
75
|
+
errors.add(:next_page_no, ErrorMessage["should be null if on the last page", "6.5"])
|
67
76
|
end
|
68
77
|
end
|
69
78
|
|
70
79
|
def current_page_no_is_consistent
|
71
80
|
if current_page_no
|
72
|
-
errors.add(:current_page_no, "is larger than the number of pages") if current_page_no > total_no_pages
|
73
|
-
errors.add(:current_page_no, "can not be less than 1") if current_page_no < 1
|
81
|
+
errors.add(:current_page_no, ErrorMessage["is larger than the number of pages", "6.5"]) if current_page_no > total_no_pages
|
82
|
+
errors.add(:current_page_no, ErrorMessage["can not be less than 1", "6.5"]) if current_page_no < 1
|
74
83
|
end
|
75
84
|
end
|
76
85
|
|
77
86
|
def total_no_results_is_consistent
|
78
87
|
if total_no_pages && total_no_results > total_no_pages * no_results_per_page
|
79
|
-
errors.add(:total_no_results, "is larger than can be retrieved through paging")
|
88
|
+
errors.add(:total_no_results, ErrorMessage["is larger than can be retrieved through paging", "6.5"])
|
80
89
|
end
|
81
90
|
if total_no_pages && total_no_results <= (total_no_pages - 1) * no_results_per_page
|
82
|
-
errors.add(:total_no_results, "could fit into a smaller number of pages")
|
91
|
+
errors.add(:total_no_results, ErrorMessage["could fit into a smaller number of pages", "6.5"])
|
83
92
|
end
|
84
93
|
end
|
85
94
|
|
@@ -90,7 +99,14 @@ module ATDIS
|
|
90
99
|
end
|
91
100
|
|
92
101
|
def self.read_json(text)
|
93
|
-
|
102
|
+
begin
|
103
|
+
data = MultiJson.load(text, :symbolize_keys => true)
|
104
|
+
interpret(data)
|
105
|
+
rescue MultiJson::LoadError => e
|
106
|
+
a = interpret({:response => []})
|
107
|
+
a.json_load_error = e.to_s
|
108
|
+
a
|
109
|
+
end
|
94
110
|
end
|
95
111
|
|
96
112
|
def previous_url
|