hdo-storting-importer 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/Gemfile +1 -1
  2. data/Rakefile +0 -1
  3. data/features/convert.feature +97 -79
  4. data/hdo-storting-importer.gemspec +5 -0
  5. data/lib/hdo/storting_importer/category.rb +16 -56
  6. data/lib/hdo/storting_importer/cli.rb +6 -34
  7. data/lib/hdo/storting_importer/committee.rb +13 -24
  8. data/lib/hdo/storting_importer/converter.rb +4 -9
  9. data/lib/hdo/storting_importer/district.rb +12 -24
  10. data/lib/hdo/storting_importer/fusion_table.rb +52 -0
  11. data/lib/hdo/storting_importer/has_json_schema.rb +85 -0
  12. data/lib/hdo/storting_importer/issue.rb +29 -60
  13. data/lib/hdo/storting_importer/party.rb +13 -24
  14. data/lib/hdo/storting_importer/promise.rb +60 -55
  15. data/lib/hdo/storting_importer/proposition.rb +61 -0
  16. data/lib/hdo/storting_importer/representative.rb +37 -70
  17. data/lib/hdo/storting_importer/schema/category.json +28 -0
  18. data/lib/hdo/storting_importer/schema/committee.json +21 -0
  19. data/lib/hdo/storting_importer/schema/district.json +21 -0
  20. data/lib/hdo/storting_importer/schema/issue.json +62 -0
  21. data/lib/hdo/storting_importer/schema/party.json +21 -0
  22. data/lib/hdo/storting_importer/schema/promise.json +42 -0
  23. data/lib/hdo/storting_importer/schema/proposition.json +34 -0
  24. data/lib/hdo/storting_importer/schema/representative.json +61 -0
  25. data/lib/hdo/storting_importer/schema/vote.json +64 -0
  26. data/lib/hdo/storting_importer/schema.json +5 -0
  27. data/lib/hdo/storting_importer/util.rb +13 -11
  28. data/lib/hdo/storting_importer/version.rb +1 -1
  29. data/lib/hdo/storting_importer/vote.rb +46 -143
  30. data/lib/hdo/storting_importer.rb +12 -3
  31. data/spec/fixtures/output/categories.json +1 -0
  32. data/spec/fixtures/output/committees.json +1 -0
  33. data/spec/fixtures/output/districts.json +1 -0
  34. data/spec/fixtures/output/issues.json +1 -0
  35. data/spec/fixtures/output/parties.json +1 -0
  36. data/spec/fixtures/output/representatives.json +1 -0
  37. data/spec/fixtures/output/votes.json +1 -0
  38. data/spec/hdo/storting_importer/category_spec.rb +29 -33
  39. data/spec/hdo/storting_importer/committee_spec.rb +29 -16
  40. data/spec/hdo/storting_importer/converter_spec.rb +3 -3
  41. data/spec/hdo/storting_importer/district_spec.rb +27 -18
  42. data/spec/hdo/storting_importer/issue_spec.rb +44 -27
  43. data/spec/hdo/storting_importer/party_spec.rb +25 -16
  44. data/spec/hdo/storting_importer/promise_spec.rb +54 -40
  45. data/spec/hdo/storting_importer/proposition_spec.rb +44 -0
  46. data/spec/hdo/storting_importer/representative_spec.rb +73 -26
  47. data/spec/hdo/storting_importer/vote_spec.rb +73 -75
  48. data/spec/spec_helper.rb +21 -1
  49. metadata +95 -3
  50. data/.gitmodules +0 -3
@@ -3,19 +3,14 @@
3
3
  module Hdo
4
4
  module StortingImporter
5
5
  class Issue
6
+ include HasJsonSchema
6
7
  include IvarEquality
7
8
  include Inspectable
8
9
 
9
10
  attr_reader :external_id, :summary, :description, :type, :status, :last_update,
10
11
  :reference, :document_group, :committee, :categories
11
12
 
12
- def self.type_name
13
- 'issue'
14
- end
15
-
16
- def self.description
17
- 'a parliament issue'
18
- end
13
+ schema_path StortingImporter.lib.join("hdo/storting_importer/schema/issue.json").to_s
19
14
 
20
15
  def self.example
21
16
  new(
@@ -32,23 +27,8 @@ module Hdo
32
27
  )
33
28
  end
34
29
 
35
- def self.xml_example(builder = Util.builder)
36
- example.to_hdo_xml(builder)
37
- end
38
-
39
- def self.fields
40
- [
41
- EXTERNAL_ID_FIELD,
42
- Field.new(:summary, true, :string, 'A (preferably one-line) summary of the issue.'),
43
- Field.new(:description, true, :string, 'A longer description of the issue.'),
44
- Field.new(:type, true, :string, 'The type of issue.'),
45
- Field.new(:status, true, :string, 'The status of the issue.'),
46
- Field.new(:lastUpdate, true, :string, 'The time the issue was last updated in the parliament.'),
47
- Field.new(:reference, true, :string, 'A reference.'),
48
- Field.new(:documentGroup, true, :string, 'What document group this issue belongs to.'),
49
- Field.new(:committee, false, :string, "What committee this issue belongs to. Should match the 'name' field in the committee type."),
50
- Field.new(:categories, false, 'list', "List of categories (matching the 'name' field of the category type).")
51
- ]
30
+ def self.json_example
31
+ Util.json_pretty example
52
32
  end
53
33
 
54
34
  def self.from_storting_doc(doc)
@@ -83,23 +63,17 @@ module Hdo
83
63
  raise
84
64
  end
85
65
 
86
- def self.from_hdo_doc(doc)
87
- doc.css("issues > issue").map { |e| from_hdo_node(e) }
88
- end
89
-
90
- def self.from_hdo_node(node)
91
- external_id = node.css("externalId").first.text
92
- summary = node.css("summary").first.text
93
- description = node.css("description").first.text
94
- type = node.css("type").first.text
95
- status = node.css("status").first.text
96
- last_update = node.css("lastUpdate").first.text
97
- reference = node.css("reference").first.text
98
- document_group = node.css("documentGroup").first.text
99
- committee = node.css("committee").first.text
100
- categories = node.css("categories category").map { |e| e.text }
101
-
102
- new external_id, summary, description, type, status, last_update, reference, document_group, committee, categories
66
+ def self.from_hash(hash)
67
+ new hash.fetch('externalId'),
68
+ hash.fetch('summary'),
69
+ hash.fetch('description'),
70
+ hash.fetch('type'),
71
+ hash.fetch('status'),
72
+ hash.fetch('lastUpdate'),
73
+ hash.fetch('reference'),
74
+ hash.fetch('documentGroup'),
75
+ hash.fetch('committee'),
76
+ hash.fetch('categories')
103
77
  end
104
78
 
105
79
  def initialize(external_id, summary, description, type, status, last_update,
@@ -120,25 +94,20 @@ module Hdo
120
94
  short_inspect_string :include => [:external_id, :summary]
121
95
  end
122
96
 
123
- def to_hdo_xml(builder = Util.builder)
124
- builder.issue do |i|
125
- i.externalId external_id
126
- i.summary summary
127
- i.description description
128
- i.type type
129
- i.status status
130
- i.lastUpdate last_update
131
- i.reference reference
132
- i.documentGroup document_group
133
- i.committee(committee) if committee
134
-
135
- if categories.any?
136
- i.categories do |cats|
137
- categories.each { |e| cats.category e }
138
- end
139
- end
140
- end
141
-
97
+ def to_hash
98
+ {
99
+ :kind => self.class.kind,
100
+ :externalId => @external_id,
101
+ :summary => @summary,
102
+ :description => @description,
103
+ :type => @type,
104
+ :status => @status,
105
+ :lastUpdate => @last_update,
106
+ :reference => @reference,
107
+ :documentGroup => @document_group,
108
+ :committee => @committee,
109
+ :categories => @categories
110
+ }
142
111
  end
143
112
 
144
113
  end
@@ -1,29 +1,20 @@
1
1
  module Hdo
2
2
  module StortingImporter
3
3
  class Party
4
+ include HasJsonSchema
4
5
  include IvarEquality
5
6
 
6
7
  attr_reader :external_id, :name
7
8
  alias_method :short_inspect, :inspect
8
9
 
9
- def self.type_name
10
- 'party'
11
- end
12
-
13
- def self.description
14
- 'a political party'
15
- end
10
+ schema_path StortingImporter.lib.join("hdo/storting_importer/schema/party.json").to_s
16
11
 
17
12
  def self.example
18
13
  new("DEM", "Democratic Party")
19
14
  end
20
15
 
21
- def self.xml_example(builder = Util.builder)
22
- example.to_hdo_xml(builder)
23
- end
24
-
25
- def self.fields
26
- [EXTERNAL_ID_FIELD, Field.new(:name, true, :string, 'The name of the party.')]
16
+ def self.json_example
17
+ Util.json_pretty example
27
18
  end
28
19
 
29
20
  def self.from_storting_doc(doc)
@@ -32,12 +23,8 @@ module Hdo
32
23
  end
33
24
  end
34
25
 
35
- def self.from_hdo_doc(doc)
36
- doc.css("parties > party").map { |e| from_hdo_node(e) }
37
- end
38
-
39
- def self.from_hdo_node(node)
40
- new node.css("externalId").first.text, node.css("name").first.text
26
+ def self.from_hash(hash)
27
+ new hash.fetch('externalId'), hash.fetch('name')
41
28
  end
42
29
 
43
30
  def initialize(external_id, name)
@@ -49,12 +36,14 @@ module Hdo
49
36
  Util.unescape_param @external_id
50
37
  end
51
38
 
52
- def to_hdo_xml(builder = Util.builder)
53
- builder.party do |party|
54
- party.externalId external_id
55
- party.name name
56
- end
39
+ def to_hash
40
+ {
41
+ :kind => self.class.kind,
42
+ :externalId => @external_id,
43
+ :name => @name
44
+ }
57
45
  end
46
+
58
47
  end
59
48
  end
60
49
  end
@@ -5,49 +5,25 @@ require 'csv'
5
5
  module Hdo
6
6
  module StortingImporter
7
7
  class Promise
8
+ include HasJsonSchema
9
+ include IvarEquality
10
+
8
11
  attr_reader :party, :body, :general, :categories, :source, :page
12
+ attr_accessor :external_id
9
13
  alias_method :general?, :general
10
14
  alias_method :short_inspect, :inspect
11
15
 
12
- def self.type_name
13
- 'promise'
14
- end
15
-
16
- def self.description
17
- 'a party promise'
18
- end
19
-
20
- def self.fields
21
- [
22
- Field.new(:party, true, :string, 'The external id of the party.'),
23
- Field.new(:general, true, :boolean, "Whether this is considered a general promise (i.e. can be ambigious whether it has been fulfilled)."),
24
- Field.new(:categories, true, :list, "List of category names (matching names imported in <a href='#input-format-category'>&lt;category&gt;</a>)"),
25
- Field.new(:source, true, :string, "The source of the promise. (TODO: this should always be a URL)"),
26
- Field.new(:body, true, :string, "The body text of the promise."),
27
- ]
28
- end
16
+ schema_path StortingImporter.lib.join("hdo/storting_importer/schema/promise.json").to_s
29
17
 
30
18
  def self.example
31
- new("H", "Stille strengere krav til orden og oppførsel for å hindre at uro ødelegger undervisningen.", true, ["GRUNNSKOLE"], "PP", 8)
32
- end
19
+ pr = new("H", "Stille strengere krav til orden og oppførsel for å hindre at uro ødelegger undervisningen.", true, ["GRUNNSKOLE"], "PP", 8)
20
+ pr.external_id = "1"
33
21
 
34
- def self.xml_example(builder = Util.builder)
35
- example.to_hdo_xml(builder)
22
+ pr
36
23
  end
37
24
 
38
- def self.from_hdo_doc(doc)
39
- doc.css("promises > promise").map { |e| from_hdo_node(e) }
40
- end
41
-
42
- def self.from_hdo_node(node)
43
- source, page = node.css("source").first.text.split(":")
44
-
45
- new node.css("party").first.text,
46
- node.css("body").first.text,
47
- node.css("general").first.text == "true",
48
- node.css("categories > category").map { |e| e.text },
49
- source,
50
- page
25
+ def self.json_example
26
+ Util.json_pretty example
51
27
  end
52
28
 
53
29
  def self.from_csv(str)
@@ -79,34 +55,63 @@ module Hdo
79
55
  end.compact
80
56
  end
81
57
 
58
+ # doesn't really belong here - data source?
82
59
  def self.from_fusion_table(table_id, api_key)
83
- url = "https://www.googleapis.com/fusiontables/v1/query"
60
+ table = FusionTable.new(api_key)
61
+
62
+ column_names = table.columns_for(table_id).map { |e| e['name'] }.map { |e| e.inspect }.join(",")
63
+ row_count = Integer(table.query("select count(rowid) from #{table_id}", :rows => true).flatten.first)
84
64
 
85
- resp = RestClient.get(url, :params => {:sql => "select * from #{table_id}", :key => api_key})
86
- MultiJson.decode(resp).fetch('rows').map { |data| new(*data) }
87
- rescue RestClient::RequestFailed => ex
88
- raise "#{ex.message}: #{ex.http_body}"
65
+ # do this in batches of 100
66
+ limit = 100
67
+ result = []
68
+
69
+ (0..row_count).step(limit) do |offset|
70
+ sql = "SELECT #{column_names},\"rowid\" FROM #{table_id} OFFSET #{offset} LIMIT #{limit}"
71
+ result.concat table.query(sql, :rows => true).map { |data| new(*data) }
72
+ end
73
+
74
+ result
75
+ end
76
+
77
+ def self.from_hash(hash)
78
+ pr = new hash.fetch('party'),
79
+ hash.fetch('body'),
80
+ hash.fetch('general'),
81
+ hash.fetch('categories'),
82
+ hash.fetch('source'),
83
+ hash.fetch('page')
84
+
85
+ pr.external_id = hash['externalId']
86
+
87
+ pr
89
88
  end
90
89
 
91
90
  def initialize(party, body, general, categories, source, page)
92
- @party = party
93
- @body = body
94
- @general = general
95
- @categories = clean_categories(categories)
96
- @source = source
97
- @page = page
91
+ @party = party.strip
92
+ @body = body.strip
93
+ @general = general
94
+ @categories = clean_categories(categories)
95
+ @source = source.strip
96
+ @page = page
97
+
98
+ @external_id = nil
98
99
  end
99
100
 
100
- def to_hdo_xml(builder = Util.builder)
101
- builder.promise do |promise|
102
- promise.party party
103
- promise.general general?
104
- promise.categories do |cats|
105
- categories.each { |e| cats.category e }
106
- end
107
- promise.source [source, page].join(":")
108
- promise.body body
109
- end
101
+ def to_hash
102
+ h = {
103
+ :kind => self.class.kind,
104
+ :party => @party,
105
+ :general => @general,
106
+ :categories => @categories,
107
+ :source => @source,
108
+ :page => @page,
109
+ :body => @body
110
+ }
111
+
112
+ h[:externalId] = @external_id if @external_id
113
+
114
+ h
110
115
  end
111
116
 
112
117
  private
@@ -0,0 +1,61 @@
1
+ module Hdo
2
+ module StortingImporter
3
+ class Proposition
4
+ include HasJsonSchema
5
+ include IvarEquality
6
+ include Inspectable
7
+
8
+ attr_reader :external_id, :description, :on_behalf_of, :body, :delivered_by
9
+
10
+ schema_path StortingImporter.lib.join("hdo/storting_importer/schema/proposition.json").to_s
11
+
12
+ def self.example
13
+ new('1234', 'description', 'on behalf of', 'body', Representative.example)
14
+ end
15
+
16
+ def self.json_example
17
+ Util.json_pretty example
18
+ end
19
+
20
+ def self.from_hash(hash)
21
+ arr = [
22
+ hash.fetch('externalId'),
23
+ hash.fetch('description'),
24
+ hash.fetch('onBehalfOf'),
25
+ hash.fetch('body')
26
+ ]
27
+
28
+ delivered_by = hash['deliveredBy']
29
+ arr << Representative.from_hash(delivered_by) if delivered_by
30
+
31
+ new(*arr)
32
+ end
33
+
34
+ def initialize(external_id, description, on_behalf_of, body, delivered_by)
35
+ @external_id = external_id
36
+ @description = description
37
+ @on_behalf_of = on_behalf_of
38
+ @body = body
39
+ @delivered_by = delivered_by
40
+ end
41
+
42
+ def short_inspect
43
+ short_inspect_string :include => [:external_id, :description, :on_behalf_of]
44
+ end
45
+
46
+ def to_hash
47
+ h = {
48
+ :kind => self.class.kind,
49
+ :externalId => @external_id,
50
+ :description => @description,
51
+ :onBehalfOf => @on_behalf_of,
52
+ :body => @body
53
+ }
54
+
55
+ h[:deliveredBy] = @delivered_by.to_hash if @delivered_by
56
+
57
+ h
58
+ end
59
+ end # Proposition
60
+ end
61
+ end
@@ -3,6 +3,7 @@
3
3
  module Hdo
4
4
  module StortingImporter
5
5
  class Representative
6
+ include HasJsonSchema
6
7
  include IvarEquality
7
8
  include Inspectable
8
9
 
@@ -11,13 +12,7 @@ module Hdo
11
12
 
12
13
  attr_accessor :vote_result
13
14
 
14
- def self.type_name
15
- 'representative'
16
- end
17
-
18
- def self.description
19
- 'a member of parliament'
20
- end
15
+ schema_path StortingImporter.lib.join("hdo/storting_importer/schema/representative.json").to_s
21
16
 
22
17
  def self.example
23
18
  new(
@@ -34,22 +29,8 @@ module Hdo
34
29
  )
35
30
  end
36
31
 
37
- def self.xml_example(builder = Util.builder)
38
- example.to_hdo_xml(builder)
39
- end
40
-
41
- def self.fields
42
- [
43
- EXTERNAL_ID_FIELD,
44
- Field.new(:firstName, true, :string, 'The first name of the representative.'),
45
- Field.new(:lastName, true, :string, 'The last name of the representative.'),
46
- Field.new(:period, true, :string, "An identifier for the period the representative is elected for."),
47
- Field.new(:district, true, :string, "The electoral district the representative belongs to. Must match the 'name' field of the district type."),
48
- Field.new(:party, true, :string, "The name of the representative's party."),
49
- Field.new(:committee, true, :list, "A (possibly empty) list of committees the representative is a member of. This should match the 'name' field of the committee type."),
50
- Field.new(:dateOfBirth, true, :string, "The representative's birth date."),
51
- Field.new(:dateOfDeath, false, :string, "The representative's death date."),
52
- ]
32
+ def self.json_example
33
+ Util.json_pretty example
53
34
  end
54
35
 
55
36
  def self.from_storting_doc(doc)
@@ -83,32 +64,21 @@ module Hdo
83
64
  )
84
65
  end
85
66
 
86
- def self.from_hdo_doc(doc)
87
- doc.css("representatives > representative").map { |e| from_hdo_node e }
88
- end
89
-
90
- def self.from_hdo_node(node)
91
- district_node = node.css("district").first
92
- district = district_node ? district_node.text : ''
93
-
94
- party_node = node.css("party").first
95
- party = party_node ? party_node.text : ''
96
-
97
- rep = new node.css("externalId").first.text,
98
- node.css("firstName").first.text,
99
- node.css("lastName").first.text,
100
- node.css("gender").first.text,
101
- node.css("dateOfBirth").first.text,
102
- node.css("dateOfDeath").first.text,
103
- district,
104
- party,
105
- node.css("committees committee").map { |e| e.text.strip },
106
- node.css("period").first.text
107
-
108
- result_node = node.css("voteResult").first
109
- rep.vote_result = result_node.text if result_node
110
-
111
- rep
67
+ def self.from_hash(hash)
68
+ v = new hash.fetch('externalId'),
69
+ hash.fetch('firstName'),
70
+ hash.fetch('lastName'),
71
+ hash.fetch('gender'),
72
+ hash.fetch('dateOfBirth'),
73
+ hash.fetch('dateOfDeath'),
74
+ hash.fetch('district'),
75
+ hash.fetch('party'),
76
+ hash.fetch('committees'),
77
+ hash.fetch('period')
78
+
79
+ v.vote_result = hash['voteResult']
80
+
81
+ v
112
82
  end
113
83
 
114
84
  def initialize(external_id, first_name, last_name, gender, date_of_birth, date_of_death, district, party, committees, period)
@@ -134,27 +104,24 @@ module Hdo
134
104
  Util.unescape_param @external_id
135
105
  end
136
106
 
137
- def to_hdo_xml(builder = Util.builder)
138
- builder.representative do |rep|
139
- rep.externalId external_id
140
- rep.firstName first_name
141
- rep.lastName last_name
142
- rep.gender gender
143
- rep.dateOfBirth date_of_birth
144
- rep.dateOfDeath date_of_death
145
- rep.district district
146
- rep.party party
147
-
148
- rep.committees do |coms|
149
- committees.each { |e| coms.committee e }
150
- end
151
-
152
- rep.period period
153
-
154
- if vote_result
155
- rep.voteResult vote_result
156
- end
157
- end
107
+ def to_hash
108
+ h = {
109
+ :kind => self.class.kind,
110
+ :externalId => @external_id,
111
+ :firstName => @first_name,
112
+ :lastName => @last_name,
113
+ :gender => @gender,
114
+ :dateOfBirth => @date_of_birth,
115
+ :dateOfDeath => @date_of_death,
116
+ :district => @district,
117
+ :party => @party,
118
+ :committees => @committees,
119
+ :period => @period
120
+ }
121
+
122
+ h[:voteResult] = @vote_result if @vote_result
123
+
124
+ h
158
125
  end
159
126
 
160
127
  end
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "hdo#category",
3
+ "description": "a parliamentary category, used to categorize issues and promises",
4
+ "type":"object",
5
+ "properties": {
6
+ "kind": {
7
+ "type": "string",
8
+ "description": "This is always 'hdo#category'",
9
+ "default": "hdo#category",
10
+ "required": true
11
+ },
12
+ "externalId": {
13
+ "type": "string"
14
+ },
15
+ "name": {
16
+ "description": "The name of the category",
17
+ "type": "string",
18
+ "required": true
19
+ },
20
+ "subCategories": {
21
+ "description": "A list of subcategories.",
22
+ "type":"array",
23
+ "items":{
24
+ "$ref": "hdo#category"
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "id": "hdo#committee",
3
+ "description": "a parliamentary committe",
4
+ "type":"object",
5
+ "properties": {
6
+ "kind": {
7
+ "type": "string",
8
+ "description": "This is always 'hdo#committee'",
9
+ "default": "hdo#committee",
10
+ "required": true
11
+ },
12
+ "externalId": {
13
+ "type": "string"
14
+ },
15
+ "name": {
16
+ "description": "The name of the committee",
17
+ "type": "string",
18
+ "required": true
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "id": "hdo#district",
3
+ "description": "an electoral district",
4
+ "type":"object",
5
+ "properties": {
6
+ "kind": {
7
+ "type": "string",
8
+ "description": "This is always 'hdo#district'",
9
+ "default": "hdo#district",
10
+ "required": true
11
+ },
12
+ "externalId": {
13
+ "type": "string"
14
+ },
15
+ "name": {
16
+ "description": "The name of the district",
17
+ "type": "string",
18
+ "required": true
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "id": "hdo#issue",
3
+ "description": "a parliament issue",
4
+ "type":"object",
5
+ "properties": {
6
+ "kind": {
7
+ "type": "string",
8
+ "description": "This is always 'hdo#issue'",
9
+ "default": "hdo#issue",
10
+ "required": true
11
+ },
12
+ "externalId": {
13
+ "type": "string",
14
+ "description": "",
15
+ "required": false
16
+ },
17
+ "summary": {
18
+ "type": "string",
19
+ "description": "A (preferably one-line) summary of the issue.",
20
+ "required": true
21
+ },
22
+ "description": {
23
+ "type": "string",
24
+ "description": "A longer description of the issue.",
25
+ "required": true
26
+ },
27
+ "type": {
28
+ "type": "string",
29
+ "description": "The type of issue.",
30
+ "required": true
31
+ },
32
+ "status": {
33
+ "type": "string",
34
+ "description": "The status of the issue.",
35
+ "required": true
36
+ },
37
+ "lastUpdate": {
38
+ "type": "string",
39
+ "description": "The date the issue was last updated in the parliament.",
40
+ "required": true
41
+ },
42
+ "reference": {
43
+ "type": "string",
44
+ "description": "A reference",
45
+ "required": true
46
+ },
47
+ "documentGroup": {
48
+ "type": "string",
49
+ "description": "What document group this issue belongs to.",
50
+ "required": true
51
+ },
52
+ "committee": {
53
+ "type": "string",
54
+ "description": "What committee this issue belongs to. Should match the 'name' field in the committee type."
55
+ },
56
+ "categories": {
57
+ "type": "array",
58
+ "description": "List of categories (matching the 'name' field of the category type).",
59
+ "items": { "type": "string" }
60
+ }
61
+ }
62
+ }