Skip to content

Commit

Permalink
Removed user/place/taxon obs export restrictions, added one that only…
Browse files Browse the repository at this point in the history
… allows one export at a time
  • Loading branch information
kueda committed Jun 15, 2020
1 parent ddf6d13 commit d4744b2
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 29 deletions.
8 changes: 7 additions & 1 deletion app/assets/javascripts/observations/export.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* eslint-disable */
var REJECT_PARAMS = ['filters_open', 'order', 'order_by', 'utf8', 'flow_task_id', 'view', 'taxon_name']
var MAX_OBSERVATIONS = 1000 // 200000;
function reloadPreview() {
$( "#limit-alert" ).hide( );
$('#previewwrapper').loadingShades()
if (window.previewRequest) {
previewRequest.abort()
Expand All @@ -14,7 +17,10 @@ function reloadPreview() {
var total = parseInt(req.getResponseHeader('X-Total-Entries')),
page = parseInt(req.getResponseHeader('X-Page')),
perPage = parseInt(req.getResponseHeader('X-Per-Page')),
start = page * perPage - perPage
start = page * perPage - perPage;
if ( total > MAX_OBSERVATIONS ) {
$( "#limit-alert" ).show( );
}
$('#previewheader .status').text((start+1) + ' - ' + (Math.min(start+perPage, total)) + ' of ' + total)
})
}
Expand Down
27 changes: 12 additions & 15 deletions app/models/observations_export_flow_task.rb
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
#encoding: utf-8
class ObservationsExportFlowTask < FlowTask
validate :must_have_query
validate :must_have_primary_filter
validate :must_have_reasonable_number_of_rows
validate :must_be_the_only_active_export, on: :create
validates_presence_of :user_id

MAX_OBSERVATIONS = 200000

before_save do |record|
record.redirect_url = FakeView.export_observations_path
end

def must_have_query
if params.keys.blank?
errors.add(:base, "Query cannot be blank")
errors.add( :base, :must_have_query )
end
end

def must_have_primary_filter
unless params[:iconic_taxa] ||
params[:iconic_taxon_id] ||
params[:taxon_id] ||
params[:place_id] ||
params[:user_id] ||
params[:q] ||
params[:projects] ||
params.keys.detect{|k| k =~ /^field:/}
errors.add(:base, "You must specify a taxon, place, user, or search query")
def must_have_reasonable_number_of_rows
if observations_count > MAX_OBSERVATIONS
errors.add( :base, :must_have_reasonable_number_of_rows )
end
end

def must_have_reasonable_number_of_rows
if observations_count > 200000
errors.add(:base, "Exports cannot contain more than 200,000 observations")
def must_be_the_only_active_export
if ObservationsExportFlowTask.where( user_id: user_id ).
where( "finished_at IS NULL AND error IS NULL" ).
exists?
errors.add( :user_id, :already_has_an_export_in_progress )
end
end

Expand Down
22 changes: 17 additions & 5 deletions app/views/observations/_exports_table.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
%table
%thead
%th
%th=t :file_size
%th=t "activerecord.attributes.observations_export_flow_task.created_at"
%th=t "activerecord.attributes.observations_export_flow_task.started_at"
%th=t "activerecord.attributes.observations_export_flow_task.finished_at"
%th=t "activerecord.attributes.observations_export_flow_task.inputs"
%tbody
- for ft in flow_tasks
%tr
%td.inline.buttonrow.smallbuttons
Expand All @@ -8,13 +16,17 @@
= t(:failed)
- else
= ft.started_at ? t(:processing) : t(:queued)
%td
%td.nobr
= ft.export_output ? number_to_human_size(ft.export_output.file.size, precision: 3) : nil
%td
%td.queued
- if ft.created_at
=l ft.created_at, format: :short
%td.started
- if ft.started_at
=l ft.started_at, format: :short
%td.finished
- if ft.finished_at
= l ft.finished_at, :format => :long
- elsif ft.started_at
= l ft.started_at, :format => :long
=l ft.finished_at, format: :short
%td
%div
%strong=t :query
Expand Down
13 changes: 8 additions & 5 deletions app/views/observations/export.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#success.success.ui
%h3 Export complete
= render 'exports_table', :flow_tasks => [@flow_task]
- if queued_export = @recent_exports.detect{|ft| ft.finished_at.blank? && ft.error.blank? }
.notice=t "views.observations.export.export_in_progress_notice"
= form_for ObservationsExportFlowTask.new, :url => flow_tasks_url, :remote => true, :html => {'data-type' => 'json'} do |f|
.column.span-24
%h3
Expand All @@ -56,6 +58,7 @@
= fti.fields_for :extra do |ftie|
= ftie.text_field :query, :type => "text", :class => "text", :id => "query", :placeholder => t('views.observations.export.query_placeholder')
#filtersplaceholder
#limit-alert.notice.hide=t "views.observations.export.limit_alert"
#previewwrapper
%h3#previewheader
.right.status.ui.meta=t :no_matching_observations
Expand Down Expand Up @@ -129,11 +132,11 @@
/ = text_field_tag :ofv_chooser, "", :placeholder => "Add an observation field", :class => "text"
%h3.inlineblock
%span.number 4
= f.submit t(:create_export, :default => "Create export"), :class => "default inline button", :data => {:loading_click => t(:loading)}
- unless @recent_exports.blank?
#recent_exports.meta.clear
%strong=t :recent_exports
= render 'exports_table', :flow_tasks => @recent_exports
= f.submit t(:create_export), :class => "default inline button", :data => {:loading_click => t(:loading)}
- unless @recent_exports.blank?
#recent_exports.meta.clear
%h4=t :recent_exports
= render 'exports_table', :flow_tasks => @recent_exports

#filters
= render "filter_fields",
Expand Down
30 changes: 27 additions & 3 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,7 @@ en:
create_a_query: Create a Query
create_an_account: Create an Account
create_an_atlas: Create an Atlas
create_export: Create Export
create_new_taxon: Create a New Taxon
create_observations: Create Observations
created: Created
Expand Down Expand Up @@ -1416,6 +1417,7 @@ en:
fields_can_only_be_edited_by_the_people_who: Fields can only be edited by the people who created them and site curators
fields_merged: Fields merged
file: File
file_size: File size
file_should_be_in_the_following_format: "File should be in the following format: taxon name, description"
fill_out_project_observation_fields: Fill out project observation fields
fill_out_your_profile: complete your profile
Expand Down Expand Up @@ -3364,6 +3366,7 @@ en:
receive_updates_from_this_project: Receive updates from this project
recent: Recent
recent_evidence_of_organism: Recent evidence of an organism
recent_exports: Recent Exports
recent_new_users: Recent New Users
recent_observations: Recent observations
recent_observations_: Recent Observations
Expand Down Expand Up @@ -5084,11 +5087,16 @@ en:
create_a_query_desc_html: |
Create an observation query just like you would elsewhere on the
site. You can also cut and paste an observations URL from another
part of the site. You must specify a
<strong>taxon</strong>, <strong>place</strong>, <strong>user</strong>,
<strong>project</strong>, or <strong>search query</strong>.
part of the site. Your query should return <strong>no more than
200,000 observations</strong>.
export_in_progress_notice: |
You have an export in progress. You'll need to wait for it to finish
before you can queue another export.
ident_by_user_desc_html: |
Columns for the current identification by %{user}
limit_alert:
Your export will be too big. Change your filters until there are
fewer than 200,000 observations.
query_placeholder: "Choose query parameters below or paste in an observations URL"
taxon_extras_help_html: "Note: these columns will slow down the generation of your export"
geo_help_html: |
Expand Down Expand Up @@ -7159,6 +7167,15 @@ en:
observed_on: date observed
observation_field_value:
value: 'value'
observations_export_flow_task:
# Date/time the task was created, i.e. the date it was added to the processing queue
created_at: Queued
# Date/time the task began processing
started_at: Started
# Date/time the task finished processing
finished_at: Finished
# Inputs to an export task, e.g. the query and the columns
inputs: Inputs
post:
title: Title
body: Body
Expand Down Expand Up @@ -7271,6 +7288,13 @@ en:
observation_id:
user_does_not_accept_fields_from_others: user does not accept fields from others
user_only_accepts_fields_from_site_curators: user only accepts fields from site curators
observations_export_flow_task:
attributes:
base:
must_have_reasonable_number_of_rows: Exports cannot contain more than 200,000 observations
must_have_query: Query cannot be blank
user_id:
already_has_an_export_in_progress: already has an export in progress
place:
attributes:
place_geometry:
Expand Down
22 changes: 22 additions & 0 deletions spec/models/observations_export_flow_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

describe ObservationsExportFlowTask do
elastic_models( Observation, Identification )
describe "validation" do
it "should not allow exports of more than 200,000 observations" do
ft = ObservationsExportFlowTask.make
allow( ft ).to receive(:observations_count).and_return( 300000 )
ft.inputs.build( extra: { query: "photos=true" } )
expect( ft ).not_to be_valid
end
it "should not allow a new export if an existing one has not run yet" do
ft = make_observations_export_flow_task
expect( ft ).to be_valid
extra_ft = ObservationsExportFlowTask.make( user: ft.user )
extra_ft.inputs.build( extra: { query: "photos=true" } )
expect( extra_ft ).not_to be_valid
end
it "should allow a new export if an existing one has not run yet but has an error" do
ft = make_observations_export_flow_task( error: "something went terribly wrong" )
expect( ft ).to be_valid
extra_ft = ObservationsExportFlowTask.make( user: ft.user )
extra_ft.inputs.build( extra: { query: "photos=true" } )
expect( extra_ft ).to be_valid
end
end
describe "run" do
before do
# not sure why the before(:each) in spec_helper may not have run yet here
Expand Down

0 comments on commit d4744b2

Please sign in to comment.