atdis 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/openaustralia/atdis.png?branch=master)](https://travis-ci.org/openaustralia/atdis) [![Coverage Status](https://coveralls.io/repos/openaustralia/atdis/badge.png?branch=master)](https://coveralls.io/r/openaustralia/atdis?branch=master) [![Code Climate](https://codeclimate.com/github/openaustralia/atdis.png)](https://codeclimate.com/github/openaustralia/atdis)
|
3
|
+
[![Build Status](https://travis-ci.org/openaustralia/atdis.png?branch=master)](https://travis-ci.org/openaustralia/atdis) [![Coverage Status](https://coveralls.io/repos/openaustralia/atdis/badge.png?branch=master)](https://coveralls.io/r/openaustralia/atdis?branch=master) [![Code Climate](https://codeclimate.com/github/openaustralia/atdis.png)](https://codeclimate.com/github/openaustralia/atdis) [![Gem Version](https://badge.fury.io/rb/atdis.png)](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
|