Skip to content

Commit 308ba54

Browse files
authored
Merge pull request #591 from alphagov/add-csv-index-response
Add a CSV index response
2 parents 4a860c1 + 4eb0750 commit 308ba54

9 files changed

Lines changed: 76 additions & 19 deletions

File tree

app/controllers/application_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def authenticate
1818
end
1919
end
2020

21+
def csv_request?
22+
request.format.symbol == :csv
23+
end
24+
2125
def json_request?
2226
request.format.symbol == :json
2327
end

app/controllers/local_petitions_controller.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ def redirect_to_constituency
6666
end
6767
end
6868

69-
def csv_request?
70-
request.format.symbol == :csv
71-
end
72-
7369
def csv_filename
7470
if action_name == 'all'
7571
"all-popular-petitions-in-#{@constituency.slug}.csv"

app/controllers/petitions_controller.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'csv'
2+
13
class PetitionsController < ApplicationController
24
include ManagingMoveParameter
35

@@ -13,9 +15,11 @@ class PetitionsController < ApplicationController
1315
before_action :redirect_to_petition_url, if: :moderated?, only: [:gathering_support, :moderation_info]
1416

1517
before_action :set_cors_headers, only: [:index, :show, :count], if: :json_request?
18+
after_action :set_content_disposition, if: :csv_request?, only: [:index]
1619

1720
respond_to :html
1821
respond_to :json, only: [:index, :show]
22+
respond_to :csv, only: [:index]
1923

2024
def index
2125
@petitions = Petition.visible.search(params)
@@ -173,4 +177,12 @@ def send_email_to_gather_sponsors(petition)
173177
def parse_emails(emails)
174178
emails.strip.split(/\r?\n/).map { |e| e.strip }
175179
end
180+
181+
def csv_filename
182+
"#{@petitions.scope}-petitions.csv"
183+
end
184+
185+
def set_content_disposition
186+
response.headers['Content-Disposition'] = "attachment; filename=#{csv_filename}"
187+
end
176188
end

app/models/concerns/browseable.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ def each(&block)
7777
results.each(&block)
7878
end
7979

80+
def find_each(&block)
81+
execute_search.find_each(&block)
82+
end
83+
8084
def facets
8185
@facets ||= Facets.new(klass)
8286
end
@@ -101,15 +105,15 @@ def page_size
101105
@page_size ||= [[params.fetch(:count, 50).to_i, 50].min, 1].max
102106
end
103107

104-
def previous_params
108+
def previous_params
105109
{}.tap do |params|
106110
params[:q] = query if query.present?
107111
params[:state] = scope
108112
params[:page] = previous_page
109113
end
110114
end
111115

112-
def next_params
116+
def next_params
113117
{}.tap do |params|
114118
params[:q] = query if query.present?
115119
params[:state] = scope

app/views/petitions/index.csv.ruby

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
csv_builder = lambda do |csv|
2+
csv << ['Petition', 'URL', 'State', 'Signatures Count']
3+
4+
@petitions.find_each do |petition|
5+
csv << [
6+
petition.action,
7+
petition_url(petition),
8+
petition.state,
9+
petition.signature_count
10+
]
11+
end
12+
end
13+
14+
if @petitions.query.present?
15+
CSV.generate(&csv_builder)
16+
else
17+
csv_cache [:petitions, @petitions.scope], expires_in: 5.minutes do
18+
CSV.generate(&csv_builder)
19+
end
20+
end

app/views/petitions/search/_results.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
<% end -%>
1111
</ol>
1212
<%= render 'paginated_results' %>
13-
<p><%= link_to "Get this data (json format)", petitions_path(:json, params.slice(:page, :state)) %></p>
13+
<p>Get this data in <%= link_to "JSON", petitions_path(:json, params.slice(:q, :page, :state)) %> or <%= link_to 'CSV', petitions_path(:csv, params.slice(:q, :state)) %> format</p>
1414
<% end %>
1515
</div>

features/support/paths.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ def url_to(page_name)
2020
when /^the feedback page$/
2121
feedback_url
2222

23+
when /^the all petitions page$/
24+
petitions_url
25+
26+
when /^the all petitions JSON page$/
27+
petitions_url(:json)
28+
2329
when /^the check for existing petitions page$/
2430
check_petitions_url
2531

@@ -47,9 +53,6 @@ def url_to(page_name)
4753
when /^the new signature page for "([^\"]*)"$/
4854
new_petition_signature_url(Petition.find_by(action: $1))
4955

50-
when /^the search results page$/
51-
search_url
52-
5356
when /^the Admin (.*)$/i
5457
admin_url($1)
5558

features/suzie_views_all_petitions.feature

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,19 @@ Feature: Suzy Signer views all petitions
9595
And I navigate to the next page of petitions
9696
Then I should see "2 of 3"
9797

98+
Scenario: Downloading the JSON data for petitions
99+
Given a set of petitions
100+
And I am on the all petitions page
101+
Then I should see all petitions
102+
And the markup should be valid
103+
When I click the JSON link
104+
Then I should be on the all petitions JSON page
105+
And the JSON should be valid
106+
107+
Scenario: Downloading the CSV data for petitions
108+
Given a set of petitions
109+
And I am on the all petitions page
110+
Then I should see all petitions
111+
And the markup should be valid
112+
When I click the CSV link
113+
Then I should get a download with the filename "all-petitions.csv"

spec/requests/disallowed_format_spec.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,18 @@
167167
end
168168
end
169169

170-
simple_html_and_json_urls = [
171-
'petitions', 'archived/petitions'
172-
]
173-
simple_html_and_json_urls.each do |simple_url|
174-
context "the #{simple_url} url" do
175-
let(:url) { "/#{simple_url}" }
176-
let(:params) { {} }
170+
context "the petitions url" do
171+
let(:url) { "/petitions" }
172+
let(:params) { {} }
177173

178-
it_behaves_like 'a route that supports html and json formats'
179-
end
174+
it_behaves_like 'a route that supports html, json and csv formats'
175+
end
176+
177+
context "the archived/petitions url" do
178+
let(:url) { "/archived/petitions" }
179+
let(:params) { {} }
180+
181+
it_behaves_like 'a route that supports html and json formats'
180182
end
181183

182184
context 'the petitions/local results url' do

0 commit comments

Comments
 (0)