From 445dc48e23ff04dfdbe818af94d9cabf4f237a42 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 11 Jun 2019 13:43:24 +0100 Subject: [PATCH 001/114] Make Embargo.expire_publishable remove embargo_duration from the batch If an request is part of a batch, expiring the embargo should also remove the `embargo_duration` from the related batch. If the `embargo_duration` remains, the batch will be treated as if it is still under embargo, and the resulting attempt read the deleted embargo will raise the following error: `undefined method `expiring_soon?' for nil:NilClass` --- app/models/alaveteli_pro/embargo.rb | 5 +++ spec/models/alaveteli_pro/embargo_spec.rb | 37 +++++++++++++++++++---- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/app/models/alaveteli_pro/embargo.rb b/app/models/alaveteli_pro/embargo.rb index bc3ef9dd84..fe50b5c356 100644 --- a/app/models/alaveteli_pro/embargo.rb +++ b/app/models/alaveteli_pro/embargo.rb @@ -95,9 +95,14 @@ def self.expiring_soon_time def self.expire_publishable beginning_of_day = Time.zone.now.beginning_of_day + where(['publish_at < ?', beginning_of_day]).find_each do |embargo| embargo.info_request.log_event('expire_embargo', {}) embargo.destroy + + if embargo.info_request.info_request_batch_id + embargo.info_request.info_request_batch.update(embargo_duration: nil) + end end end diff --git a/spec/models/alaveteli_pro/embargo_spec.rb b/spec/models/alaveteli_pro/embargo_spec.rb index a8bf133f5e..cf2dc0ae13 100644 --- a/spec/models/alaveteli_pro/embargo_spec.rb +++ b/spec/models/alaveteli_pro/embargo_spec.rb @@ -203,12 +203,7 @@ describe '.expire_publishable' do - context 'for an embargo whose publish_at date has passed' do - let!(:embargo) do - FactoryBot.create(:embargo, :publish_at => Time.now - 2.days) - end - - let!(:info_request) { embargo.info_request } + shared_examples_for 'successful_expiry' do it 'deletes the embargo' do AlaveteliPro::Embargo.expire_publishable @@ -224,6 +219,36 @@ expect(expiry_events.size).to eq 1 end + end + + context 'for an embargo whose publish_at date has passed' do + let!(:embargo) do + FactoryBot.create(:embargo, publish_at: Time.now - 2.days) + end + + let!(:info_request) { embargo.info_request } + + it_behaves_like 'successful_expiry' + + context 'when the request is part of a batch' do + let(:info_request_batch) { FactoryBot.create(:info_request_batch) } + + before do + info_request.info_request_batch = info_request_batch + info_request_batch.sent_at = info_request.created_at + info_request_batch.embargo_duration = '3_months' + info_request_batch.save! + info_request.save! + end + + it_behaves_like 'successful_expiry' + + it 'deletes the embargo_duration from the batch' do + AlaveteliPro::Embargo.expire_publishable + expect(info_request_batch.reload.embargo_duration).to be_nil + end + end + context 'when the request has use_notifications: true' do it 'notifies the user of the event' do From f8b6a4753375a810237a936dd6b6d240cb5214c6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 3 Jun 2019 11:50:14 +0100 Subject: [PATCH 002/114] Enable some more cops Nothing massively controversial here IMO. --- .ruby-style.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.ruby-style.yml b/.ruby-style.yml index 3c6ccc938c..b778c0c849 100644 --- a/.ruby-style.yml +++ b/.ruby-style.yml @@ -112,12 +112,12 @@ Layout/EndOfLine: Layout/ExtraSpacing: Description: 'Do not use unnecessary spacing.' - Enabled: false + Enabled: true Layout/InitialIndentation: Description: >- Checks the indentation of the first non-blank non-comment line in a file. - Enabled: false + Enabled: true Layout/FirstParameterIndentation: Description: 'Checks the indentation of the first parameter in a method call.' @@ -125,7 +125,7 @@ Layout/FirstParameterIndentation: Layout/IndentationConsistency: Description: 'Keep indentation straight.' - Enabled: false + Enabled: true Layout/IndentationWidth: Description: 'Use 2 spaces for indentation.' @@ -142,7 +142,7 @@ Layout/IndentAssignment: Description: >- Checks the indentation of the first line of the right-hand-side of a multi-line assignment. - Enabled: false + Enabled: true Layout/IndentHash: Description: 'Checks the indentation of the first key in a hash literal.' @@ -158,7 +158,7 @@ Layout/MultilineArrayBraceLayout: Checks that the closing brace in an array literal is either on the same line as the last array element, or a new line. - Enabled: false + Enabled: true Layout/MultilineBlockLayout: Description: 'Ensures newlines after multiline block do statements.' @@ -196,7 +196,7 @@ Layout/MultilineOperationIndentation: Description: >- Checks indentation of binary operations that span more than one line. - Enabled: false + Enabled: true Layout/RescueEnsureAlignment: Description: 'Align rescues and ensures correctly.' @@ -206,7 +206,7 @@ Layout/SpaceBeforeFirstArg: Description: >- Checks that exactly one space is used between a method name and the first argument for method calls without parentheses. - Enabled: false + Enabled: true Layout/SpaceAfterColon: Description: 'Use spaces after colons.' @@ -239,7 +239,7 @@ Layout/SpaceBeforeBlockBraces: Description: >- Checks that the left block brace has or doesn't have space before it. - Enabled: false + Enabled: true Layout/SpaceBeforeComma: Description: 'No spaces before commas.' @@ -253,14 +253,14 @@ Layout/SpaceBeforeComment: Layout/SpaceBeforeSemicolon: Description: 'No spaces before semicolons.' - Enabled: false + Enabled: true Layout/SpaceInsideBlockBraces: Description: >- Checks that block braces have or don't have surrounding space. For blocks taking parameters, checks that the left brace has or doesn't have trailing space. - Enabled: false + Enabled: true Layout/SpaceAroundBlockParameters: Description: 'Checks the spacing inside and after block parameters pipes.' From 637618ff16aaa15669fdf4cb43985ff06c66a917 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 09:22:09 +0100 Subject: [PATCH 003/114] Correct extra spacing Command: `bundle exec rubocop --only Layout/ExtraSpacing --auto-correct` --- app/controllers/public_body_controller.rb | 4 ++-- app/controllers/request_controller.rb | 2 +- app/controllers/track_controller.rb | 2 +- app/controllers/user_controller.rb | 2 +- app/models/alaveteli_pro/embargo.rb | 2 +- app/models/alaveteli_pro/request_filter.rb | 2 +- app/models/info_request.rb | 2 +- app/models/public_body.rb | 2 +- config/routes.rb | 4 ++-- db/migrate/001_create_users.rb | 2 +- db/migrate/002_add_sessions.rb | 2 +- db/migrate/004_create_info_requests.rb | 2 +- db/migrate/005_create_public_bodies.rb | 2 +- db/migrate/006_version_public_body.rb | 2 +- db/migrate/007_add_public_body_editor_notes.rb | 2 +- db/migrate/008_request_has_public_body.rb | 2 +- db/migrate/009_create_outgoing_messages.rb | 2 +- ...ve_public_body_id_from_outgoing_messages.rb | 2 +- db/migrate/011_add_created_updated_fields.rb | 2 +- db/migrate/012_add_sent_outgoing_message.rb | 2 +- db/migrate/013_create_incoming_messages.rb | 2 +- db/migrate/014_create_post_redirects.rb | 2 +- .../015_add_email_token_to_post_redirects.rb | 2 +- .../016_add_reasons_to_post_redirects.rb | 2 +- db/migrate/017_add_email_confirmed_to_users.rb | 2 +- ...18_add_response_type_to_incoming_message.rb | 2 +- .../021_remove_contains_information_default.rb | 2 +- db/migrate/022_create_info_request_events.rb | 2 +- .../023_outgoing_message_last_sent_at.rb | 2 +- .../024_add_is_bounce_to_incoming_messages.rb | 2 +- .../025_add_followup_to_outgoing_message.rb | 2 +- db/migrate/026_add_many_null_constraints.rb | 2 +- db/migrate/027_change_classification_system.rb | 2 +- .../028_give_incoming_messages_events.rb | 2 +- db/migrate/029_add_describe_status_history.rb | 2 +- db/migrate/030_add_some_indices.rb | 2 +- .../031_add_indices_for_session_deletion.rb | 2 +- db/migrate/032_addforeignkeys.rb | 2 +- db/migrate/033_add_prominence.rb | 2 +- db/migrate/034_run_solr_indexing.rb | 2 +- db/migrate/035_track_overdue_alerts.rb | 2 +- db/migrate/036_add_public_body_tags.rb | 2 +- db/migrate/037_add_url_name.rb | 2 +- db/migrate/038_add_more_url_names.rb | 2 +- db/migrate/039_request_url_names.rb | 2 +- db/migrate/040_email_is_unique.rb | 2 +- db/migrate/041_index_requests_with_solr.rb | 2 +- db/migrate/042_unique_user_urls.rb | 2 +- db/migrate/043_remove_complaint_email.rb | 2 +- db/migrate/044_remove_is_bounce.rb | 2 +- .../045_add_circumstance_to_post_redirect.rb | 2 +- .../046_add_last_event_id_to_alert_table.rb | 2 +- db/migrate/047_add_calculated_state.rb | 2 +- db/migrate/048_add_calculated_state_at.rb | 2 +- db/migrate/049_track_things.rb | 2 +- db/migrate/050_improve_track_things.rb | 2 +- .../051_add_track_things_unique_indices.rb | 2 +- .../052_include_event_foreign_references.rb | 2 +- db/migrate/053_acts_as_xapian_migration.rb | 2 +- db/migrate/054_allow_longer_comments.rb | 2 +- db/migrate/055_stop_new_responses.rb | 2 +- db/migrate/056_add_attachment_text.rb | 2 +- db/migrate/057_add_law_used.rb | 2 +- db/migrate/058_remove_sessions.rb | 2 +- db/migrate/059_add_url_notes.rb | 2 +- db/migrate/060_add_cached_main_text.rb | 2 +- db/migrate/061_include_responses_in_tracks.rb | 2 +- db/migrate/062_add_comments.rb | 2 +- db/migrate/063_add_admin_users.rb | 2 +- db/migrate/064_indices_for_annotations.rb | 2 +- db/migrate/065_add_comments_to_user_track.rb | 2 +- db/migrate/066_add_first_letter.rb | 2 +- db/migrate/067_factor_out_raw_email.rb | 2 +- db/migrate/068_add_censor_table.rb | 2 +- db/migrate/069_add_what_doing.rb | 2 +- db/migrate/070_sent_are_waiting_response.rb | 2 +- db/migrate/071_add_exim_log.rb | 2 +- db/migrate/072_add_publication_scheme.rb | 2 +- db/migrate/073_add_ban_user.rb | 2 +- db/migrate/074_create_holidays.rb | 2 +- db/migrate/075_add_charity_number.rb | 2 +- db/migrate/076_add_indices.rb | 2 +- db/migrate/077_add_exim_log_index.rb | 2 +- db/migrate/078_expand_stop_new_responses.rb | 2 +- db/migrate/079_add_profile_photo.rb | 2 +- .../080_cache_only_clipped_attachment_text.rb | 2 +- db/migrate/081_add_event_prominence.rb | 2 +- db/migrate/082_change_raw_email_to_binary.rb | 2 +- db/migrate/083_add_indices_track_sent.rb | 2 +- db/migrate/084_alter_profile_photo.rb | 2 +- db/migrate/085_draft_profile_photo.rb | 2 +- .../086_allow_null_profile_photo_user.rb | 2 +- db/migrate/087_add_about_me.rb | 2 +- db/migrate/088_public_body_machine_tags.rb | 2 +- db/migrate/089_remove_charity_number.rb | 2 +- db/migrate/090_remove_tag_uniqueness.rb | 2 +- db/migrate/091_add_censor_rules_indices.rb | 2 +- db/migrate/092_cache_only_marked_body_text.rb | 2 +- db/migrate/093_move_to_has_tag_string.rb | 2 +- db/migrate/094_remove_old_tags_foreign_key.rb | 2 +- db/migrate/095_add_post_redirect_user_index.rb | 2 +- db/migrate/096_create_translation_tables.rb | 2 +- db/migrate/097_add_comment_locale.rb | 2 +- db/migrate/098_fix_public_body_translations.rb | 2 +- db/migrate/099_move_raw_email_to_filesystem.rb | 2 +- .../100_remove_redundant_raw_email_columns.rb | 2 +- db/migrate/101_add_hash_to_info_request.rb | 2 +- db/migrate/102_add_locale_to_users.rb | 2 +- db/migrate/103_add_user_bounce_columns.rb | 2 +- db/migrate/104_create_foi_attachments.rb | 2 +- db/migrate/105_extend_incoming_message.rb | 2 +- .../106_add_hex_digest_to_foi_attachment.rb | 2 +- ...dd_date_parsed_field_to_incoming_message.rb | 2 +- .../108_change_safe_mail_from_to_mail_from.rb | 2 +- db/migrate/109_change_sent_at_to_datetime.rb | 2 +- db/migrate/110_add_user_no_limit.rb | 2 +- db/migrate/111_create_purge_requests.rb | 2 +- db/migrate/112_add_api_key_to_public_bodies.rb | 2 +- ...113_add_external_fields_to_info_requests.rb | 2 +- ...ttention_requested_flag_to_info_requests.rb | 2 +- .../115_add_receive_email_alerts_to_user.rb | 2 +- db/migrate/116_add_censor_rule_regexp.rb | 2 +- db/migrate/117_create_sessions.rb | 2 +- db/migrate/118_remove_sessions_again.rb | 2 +- ...5640_correct_external_request_constraint.rb | 2 +- ...910153022_create_request_classifications.rb | 2 +- ...add_raw_email_index_to_incoming_messages.rb | 2 +- ...6_add_info_request_id_index_to_exim_logs.rb | 2 +- ..._index_to_incoming_and_outgoing_messages.rb | 2 +- ...ming_message_id_index_to_foi_attachments.rb | 2 +- ...13004_add_indexes_to_info_request_events.rb | 2 +- ...0_add_public_body_index_to_info_requests.rb | 2 +- ...12114022_add_user_index_to_info_requests.rb | 2 +- ...add_info_requests_count_to_public_bodies.rb | 2 +- ...oming_message_index_to_outgoing_messages.rb | 2 +- ..._event_index_to_track_things_sent_emails.rb | 2 +- ...t_index_to_user_info_request_sent_alerts.rb | 2 +- ...updated_at_index_to_public_body_versions.rb | 2 +- ...404_add_comments_allowed_to_info_request.rb | 2 +- .../20121010214348_rename_exim_log_tables.rb | 2 +- .../20121022031914_add_disclosure_log.rb | 2 +- ...emove_prominence_from_info_request_event.rb | 2 +- ...45325_add_prominence_to_incoming_message.rb | 2 +- ...dd_prominence_reason_to_incoming_message.rb | 2 +- ...0816150110_add_statistics_to_public_body.rb | 2 +- ...dd_prominence_fields_to_outgoing_message.rb | 2 +- ...1140_add_can_make_batch_requests_to_user.rb | 2 +- ...131024114346_create_info_request_batches.rb | 2 +- ...4152540_add_body_to_info_request_batches.rb | 2 +- .../20131101155844_add_stats_denominator.rb | 2 +- ...o_request_batch_public_bodies_join_table.rb | 2 +- ...135622_add_sent_at_to_info_request_batch.rb | 2 +- ...52641_create_public_body_change_requests.rb | 2 +- .../20140325120619_create_spam_addresses.rb | 2 +- ..._add_default_short_name_to_public_bodies.rb | 2 +- ...20140528110536_update_track_things_index.rb | 2 +- ...eate_public_body_headings_and_categories.rb | 2 +- ...31107_create_category_translation_tables.rb | 2 +- ...1132719_add_index_to_info_request_events.rb | 2 +- ...display_order_to_categories_and_headings.rb | 2 +- .../20140824191444_create_widget_votes.rb | 2 +- .../20151006101417_add_otp_enabled_to_users.rb | 2 +- ...151006104552_add_otp_secret_key_to_users.rb | 2 +- ...51006104739_add_counter_for_otp_to_users.rb | 2 +- ..._requests_visible_count_to_public_bodies.rb | 2 +- ...nger_length_for_track_things_track_query.rb | 2 +- ..._last_public_response_at_to_info_request.rb | 2 +- ...26154304_add_confirmed_not_spam_to_users.rb | 2 +- ...d_reject_incoming_at_mta_to_info_request.rb | 2 +- ..._rejected_incoming_count_to_info_request.rb | 2 +- ...160613145644_add_comments_count_to_users.rb | 2 +- ...3151127_add_info_requests_count_to_users.rb | 2 +- ...13151912_add_track_things_count_to_users.rb | 2 +- ...d_request_classifications_count_to_users.rb | 2 +- ...blic_body_change_requests_count_to_users.rb | 2 +- ..._add_info_request_batches_count_to_users.rb | 2 +- ...1155339_remove_comment_type_from_comment.rb | 2 +- ..._add_delivery_status_to_mail_server_logs.rb | 2 +- .../20161006142352_create_flipper_tables.rb | 2 +- .../20161101110656_create_pro_accounts.rb | 2 +- db/migrate/20161101151318_create_embargoes.rb | 2 +- ...0161116121007_create_draft_info_requests.rb | 2 +- .../20161128095350_add_duration_to_embargo.rb | 2 +- ...ial_request_last_sent_at_to_info_request.rb | 2 +- ...ate_response_required_by_to_info_request.rb | 2 +- ..._date_very_overdue_after_to_info_request.rb | 2 +- ...20161207184708_create_embargo_extensions.rb | 2 +- ...ming_initial_request_id_to_info_requests.rb | 2 +- ...01547_add_attention_requested_to_comment.rb | 2 +- .../20170227140831_rolify_create_roles.rb | 2 +- ...163735_create_draft_info_request_batches.rb | 2 +- ...info_request_batches_public_bodies_table.rb | 2 +- ...0316170248_edit_info_request_batch_index.rb | 4 ++-- ...rgo_duration_to_draft_info_request_batch.rb | 2 +- ...d_embargo_duration_to_info_request_batch.rb | 2 +- ...8_create_alaveteli_pro_request_summaries.rb | 2 +- ...2141214_add_unique_index_to_summarisable.rb | 2 +- ...0170412143304_make_summarisable_not_null.rb | 2 +- ...170412145313_add_user_to_request_summary.rb | 2 +- ...alaveteli_pro_request_summary_categories.rb | 2 +- ...allow_user_to_be_null_on_request_summary.rb | 2 +- ...0414140927_create_incoming_message_error.rb | 2 +- ...nd_request_updated_at_to_request_summary.rb | 2 +- ...08_add_use_notifications_to_info_request.rb | 2 +- .../20170516120853_create_notifications.rb | 2 +- ...516132204_add_daily_summary_time_to_user.rb | 2 +- ...1753_add_last_event_time_to_info_request.rb | 2 +- ...nd_request_updated_at_on_request_summary.rb | 2 +- ...p_unconventional_public_body_constraints.rb | 2 +- ...1302_drop_public_body_translated_columns.rb | 2 +- ...70718261524_add_expiring_notification_at.rb | 2 +- ...170726114401_add_expired_to_notification.rb | 2 +- ...48_add_stripe_customer_id_to_pro_account.rb | 2 +- .../20170914164031_remove_purge_request.rb | 2 +- .../20170922160120_remove_admin_level.rb | 2 +- .../20171207140915_create_announcements.rb | 2 +- ...207140945_create_announcement_dismissals.rb | 2 +- .../20171222121709_change_user_salt_null.rb | 2 +- ...12135329_fix_broken_migration_timestamps.rb | 2 +- ...154555_add_timestamps_to_foi_attachments.rb | 2 +- ...0180418154949_add_timestamps_to_holidays.rb | 2 +- ...30_add_updated_at_to_info_request_events.rb | 2 +- ...8155632_add_timestamps_to_profile_photos.rb | 2 +- ...timestamps_to_public_body_category_links.rb | 2 +- ...add_timestamps_to_public_body_categories.rb | 2 +- ...8_add_timestamps_to_public_body_headings.rb | 2 +- ...80418160048_add_timestamps_to_raw_emails.rb | 2 +- ...estamps_to_user_info_request_sent_alerts.rb | 2 +- ...05_add_updated_at_to_has_tag_string_tags.rb | 2 +- ...06_add_timestamps_to_acts_as_xapian_jobs.rb | 2 +- .../20180801085621_add_closed_at_to_users.rb | 2 +- ...incoming_messages_count_to_info_requests.rb | 2 +- lib/data_export.rb | 2 +- lib/mail_handler/mail_handler.rb | 2 +- lib/tasks/graphs.rake | 18 +++++++++--------- lib/tasks/themes.rake | 2 +- lib/tasks/translation.rake | 4 ++-- lib/use_spans_for_errors.rb | 2 +- lib/xapian_queries.rb | 2 +- .../embargo_extensions_controller_spec.rb | 2 +- .../stripe_webhooks_controller_spec.rb | 2 +- spec/controllers/general_controller_spec.rb | 2 +- spec/controllers/user_controller_spec.rb | 14 +++++++------- .../users/sessions_controller_spec.rb | 4 ++-- spec/helpers/admin_users_helper_spec.rb | 4 ++-- spec/integration/download_request_spec.rb | 4 ++-- spec/integration/localisation_spec.rb | 6 +++--- spec/lib/alaveteli_mail_poller_spec.rb | 8 ++++---- spec/lib/alaveteli_rate_limiter/window_spec.rb | 4 ++-- spec/lib/data_export_spec.rb | 4 ++-- spec/models/alaveteli_pro/embargo_spec.rb | 2 +- spec/models/incoming_message_spec.rb | 2 +- spec/models/info_request_spec.rb | 4 ++-- spec/models/public_body_spec.rb | 2 +- spec/models/user_spec.rb | 4 ++-- 255 files changed, 285 insertions(+), 285 deletions(-) diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index fc89e1787c..2144556523 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -22,7 +22,7 @@ def show end if MySociety::Format.simplify_url_part(params[:url_name], 'body') != params[:url_name] - redirect_to :url_name => MySociety::Format.simplify_url_part(params[:url_name], 'body'), :status => :moved_permanently + redirect_to :url_name => MySociety::Format.simplify_url_part(params[:url_name], 'body'), :status => :moved_permanently return end @@ -38,7 +38,7 @@ def show end # If found by historic name, or alternate locale name, redirect to new name - if @public_body.url_name != params[:url_name] + if @public_body.url_name != params[:url_name] redirect_to :url_name => @public_body.url_name return end diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 5682e17f97..ebfdb1d85d 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -222,7 +222,7 @@ def new_batch # TODO: Decide if we make batch requesters describe their undescribed requests # before being able to make a new batch request - if !authenticated_user.can_file_requests? + if !authenticated_user.can_file_requests? @details = authenticated_user.can_fail_html render :template => 'user/banned' and return end diff --git a/app/controllers/track_controller.rb b/app/controllers/track_controller.rb index 99e4160903..58e69405ae 100644 --- a/app/controllers/track_controller.rb +++ b/app/controllers/track_controller.rb @@ -54,7 +54,7 @@ def track_public_body @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) raise ActiveRecord::RecordNotFound.new("None found") if @public_body.nil? # If found by historic name, or alternate locale name, redirect to new name - if @public_body.url_name != params[:url_name] + if @public_body.url_name != params[:url_name] redirect_to track_public_body_url(:url_name => @public_body.url_name, :feed => params[:feed], :event_type => params[:event_type]) return end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index eac2d9abd2..b5a3519cd6 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -381,7 +381,7 @@ def set_in_pro_area def normalize_url_name unless MySociety::Format.simplify_url_part(params[:url_name], 'user') == params[:url_name] - redirect_to :url_name => MySociety::Format.simplify_url_part(params[:url_name], 'user'), :status => :moved_permanently + redirect_to :url_name => MySociety::Format.simplify_url_part(params[:url_name], 'user'), :status => :moved_permanently end end diff --git a/app/models/alaveteli_pro/embargo.rb b/app/models/alaveteli_pro/embargo.rb index bc3ef9dd84..bd8edc3dd5 100644 --- a/app/models/alaveteli_pro/embargo.rb +++ b/app/models/alaveteli_pro/embargo.rb @@ -51,7 +51,7 @@ class Embargo < ApplicationRecord scope :expiring, -> { where("publish_at <= ?", expiring_soon_time) } def set_default_duration - self.embargo_duration ||= "3_months" + self.embargo_duration ||= "3_months" end def allowed_durations diff --git a/app/models/alaveteli_pro/request_filter.rb b/app/models/alaveteli_pro/request_filter.rb index 5eb587e6e8..188b1fec75 100644 --- a/app/models/alaveteli_pro/request_filter.rb +++ b/app/models/alaveteli_pro/request_filter.rb @@ -123,7 +123,7 @@ def phase_filters InfoRequest::State.phases.map{ |phase| { :param => phase[:scope].to_s, :value => phase[:scope], :label => phase[:label], - :capital_label => phase[:capital_label] } } + :capital_label => phase[:capital_label] } } end def filter_attributes diff --git a/app/models/info_request.rb b/app/models/info_request.rb index b68befc1c5..1d5fdd5ef2 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -1048,7 +1048,7 @@ def base_calculate_status def calculate_event_states curr_state = nil for event in info_request_events.reverse - event.xapian_mark_needs_index # we need to reindex all events in order to update their latest_* terms + event.xapian_mark_needs_index # we need to reindex all events in order to update their latest_* terms if curr_state.nil? if event.described_state curr_state = event.described_state diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 0482b990da..46c0288d3a 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -476,7 +476,7 @@ def self.import_csv_from_file(csv_filename, tag, tag_behaviour, dry_run, editor, # Parse the first line as a field list if it starts with '#' if line==1 and row.first.to_s =~ /^#(.*)$/ - row[0] = row[0][1..-1] # Remove the # sign on first field + row[0] = row[0][1..-1] # Remove the # sign on first field row.each_with_index {|field, i| field_names[field] = i} next end diff --git a/config/routes.rb b/config/routes.rb index 9601592fda..8b7202ee24 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -449,7 +449,7 @@ #### #### AdminPublicBodyHeading controller - scope '/admin', :as => 'admin' do + scope '/admin', :as => 'admin' do resources :headings, :controller => 'admin_public_body_headings', :except => [:index] do @@ -475,7 +475,7 @@ #### #### AdminPublicBodyChangeRequest controller - scope '/admin', :as => 'admin' do + scope '/admin', :as => 'admin' do resources :change_requests, :controller => 'admin_public_body_change_requests', :only => [:edit, :update] diff --git a/db/migrate/001_create_users.rb b/db/migrate/001_create_users.rb index 919b2102b0..18dd6bc2c1 100644 --- a/db/migrate/001_create_users.rb +++ b/db/migrate/001_create_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateUsers < ActiveRecord::Migration[4.2] # 1.2 +class CreateUsers < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :users do |t| t.column :email, :string diff --git a/db/migrate/002_add_sessions.rb b/db/migrate/002_add_sessions.rb index 6e6bcecd97..abe72c9996 100644 --- a/db/migrate/002_add_sessions.rb +++ b/db/migrate/002_add_sessions.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddSessions < ActiveRecord::Migration[4.2] # 1.2 +class AddSessions < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :sessions do |t| t.column :session_id, :string diff --git a/db/migrate/004_create_info_requests.rb b/db/migrate/004_create_info_requests.rb index b8d9654096..fbbc37224d 100644 --- a/db/migrate/004_create_info_requests.rb +++ b/db/migrate/004_create_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateInfoRequests < ActiveRecord::Migration[4.2] # 1.2 +class CreateInfoRequests < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :info_requests do |t| t.column :title, :text diff --git a/db/migrate/005_create_public_bodies.rb b/db/migrate/005_create_public_bodies.rb index 724cee27e9..9b3c96ba75 100644 --- a/db/migrate/005_create_public_bodies.rb +++ b/db/migrate/005_create_public_bodies.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreatePublicBodies < ActiveRecord::Migration[4.2] # 1.2 +class CreatePublicBodies < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :public_bodies do |t| t.column :name, :text diff --git a/db/migrate/006_version_public_body.rb b/db/migrate/006_version_public_body.rb index feefcaeddf..d0fcd717c9 100644 --- a/db/migrate/006_version_public_body.rb +++ b/db/migrate/006_version_public_body.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class VersionPublicBody < ActiveRecord::Migration[4.2] # 1.2 +class VersionPublicBody < ActiveRecord::Migration[4.2] # 1.2 def self.up PublicBody.create_versioned_table diff --git a/db/migrate/007_add_public_body_editor_notes.rb b/db/migrate/007_add_public_body_editor_notes.rb index 44c9ffaa0a..bae55b5297 100644 --- a/db/migrate/007_add_public_body_editor_notes.rb +++ b/db/migrate/007_add_public_body_editor_notes.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPublicBodyEditorNotes < ActiveRecord::Migration[4.2] # 1.2 +class AddPublicBodyEditorNotes < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :public_bodies, :last_edit_editor, :string add_column :public_bodies, :last_edit_comment, :string diff --git a/db/migrate/008_request_has_public_body.rb b/db/migrate/008_request_has_public_body.rb index 65a56aa238..5c5fb1579d 100644 --- a/db/migrate/008_request_has_public_body.rb +++ b/db/migrate/008_request_has_public_body.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RequestHasPublicBody < ActiveRecord::Migration[4.2] # 1.2 +class RequestHasPublicBody < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :info_requests, :public_body_id, :integer end diff --git a/db/migrate/009_create_outgoing_messages.rb b/db/migrate/009_create_outgoing_messages.rb index 6e2540946b..e64ce8789e 100644 --- a/db/migrate/009_create_outgoing_messages.rb +++ b/db/migrate/009_create_outgoing_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateOutgoingMessages < ActiveRecord::Migration[4.2] # 1.2 +class CreateOutgoingMessages < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :outgoing_messages do |t| t.column :info_request_id, :integer diff --git a/db/migrate/010_remove_public_body_id_from_outgoing_messages.rb b/db/migrate/010_remove_public_body_id_from_outgoing_messages.rb index 5b037b76c5..66b539d116 100644 --- a/db/migrate/010_remove_public_body_id_from_outgoing_messages.rb +++ b/db/migrate/010_remove_public_body_id_from_outgoing_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemovePublicBodyIdFromOutgoingMessages < ActiveRecord::Migration[4.2] # 1.2 +class RemovePublicBodyIdFromOutgoingMessages < ActiveRecord::Migration[4.2] # 1.2 def self.up remove_column :outgoing_messages, :public_body_id end diff --git a/db/migrate/011_add_created_updated_fields.rb b/db/migrate/011_add_created_updated_fields.rb index 0ce9955432..8b7a553bfd 100644 --- a/db/migrate/011_add_created_updated_fields.rb +++ b/db/migrate/011_add_created_updated_fields.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCreatedUpdatedFields < ActiveRecord::Migration[4.2] # 1.2 +class AddCreatedUpdatedFields < ActiveRecord::Migration[4.2] # 1.2 def self.up # InfoRequest add_column :info_requests, :created_at, :datetime diff --git a/db/migrate/012_add_sent_outgoing_message.rb b/db/migrate/012_add_sent_outgoing_message.rb index 35b4fe8d58..a7fb6f09d7 100644 --- a/db/migrate/012_add_sent_outgoing_message.rb +++ b/db/migrate/012_add_sent_outgoing_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddSentOutgoingMessage < ActiveRecord::Migration[4.2] # 1.2 +class AddSentOutgoingMessage < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :outgoing_messages, :sent_at, :datetime end diff --git a/db/migrate/013_create_incoming_messages.rb b/db/migrate/013_create_incoming_messages.rb index 3e11a2d966..54c5c88567 100644 --- a/db/migrate/013_create_incoming_messages.rb +++ b/db/migrate/013_create_incoming_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateIncomingMessages < ActiveRecord::Migration[4.2] # 1.2 +class CreateIncomingMessages < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :incoming_messages do |t| t.column :info_request_id, :integer diff --git a/db/migrate/014_create_post_redirects.rb b/db/migrate/014_create_post_redirects.rb index bfb37f50f0..e83b851fc0 100644 --- a/db/migrate/014_create_post_redirects.rb +++ b/db/migrate/014_create_post_redirects.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreatePostRedirects < ActiveRecord::Migration[4.2] # 1.2 +class CreatePostRedirects < ActiveRecord::Migration[4.2] # 1.2 def self.up create_table :post_redirects do |t| t.column :token, :text diff --git a/db/migrate/015_add_email_token_to_post_redirects.rb b/db/migrate/015_add_email_token_to_post_redirects.rb index 59e7a742cf..27c1cdaf60 100644 --- a/db/migrate/015_add_email_token_to_post_redirects.rb +++ b/db/migrate/015_add_email_token_to_post_redirects.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEmailTokenToPostRedirects < ActiveRecord::Migration[4.2] # 1.2 +class AddEmailTokenToPostRedirects < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :post_redirects, :email_token, :text end diff --git a/db/migrate/016_add_reasons_to_post_redirects.rb b/db/migrate/016_add_reasons_to_post_redirects.rb index faf3af8d24..af75347f19 100644 --- a/db/migrate/016_add_reasons_to_post_redirects.rb +++ b/db/migrate/016_add_reasons_to_post_redirects.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddReasonsToPostRedirects < ActiveRecord::Migration[4.2] # 1.2 +class AddReasonsToPostRedirects < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :post_redirects, :reason_params_yaml, :text add_column :post_redirects, :user_id, :integer diff --git a/db/migrate/017_add_email_confirmed_to_users.rb b/db/migrate/017_add_email_confirmed_to_users.rb index 3f212f52a1..01ab97a2cf 100644 --- a/db/migrate/017_add_email_confirmed_to_users.rb +++ b/db/migrate/017_add_email_confirmed_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEmailConfirmedToUsers < ActiveRecord::Migration[4.2] # 1.2 +class AddEmailConfirmedToUsers < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :users, :email_confirmed, :boolean, :default => false end diff --git a/db/migrate/018_add_response_type_to_incoming_message.rb b/db/migrate/018_add_response_type_to_incoming_message.rb index 3af51491f7..f168f596e6 100644 --- a/db/migrate/018_add_response_type_to_incoming_message.rb +++ b/db/migrate/018_add_response_type_to_incoming_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddResponseTypeToIncomingMessage < ActiveRecord::Migration[4.2] # 1.2 +class AddResponseTypeToIncomingMessage < ActiveRecord::Migration[4.2] # 1.2 def self.up add_column :incoming_messages, :user_classified, :boolean, :default => false add_column :incoming_messages, :contains_information, :boolean, :default => false diff --git a/db/migrate/021_remove_contains_information_default.rb b/db/migrate/021_remove_contains_information_default.rb index 9c07181ba2..49b6ef7632 100644 --- a/db/migrate/021_remove_contains_information_default.rb +++ b/db/migrate/021_remove_contains_information_default.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveContainsInformationDefault < ActiveRecord::Migration[4.2] # 1.2 +class RemoveContainsInformationDefault < ActiveRecord::Migration[4.2] # 1.2 def self.up change_column :incoming_messages, :contains_information, :boolean, :default => nil drop_table :rejection_reasons diff --git a/db/migrate/022_create_info_request_events.rb b/db/migrate/022_create_info_request_events.rb index 23039e5b26..26ec55f8f6 100644 --- a/db/migrate/022_create_info_request_events.rb +++ b/db/migrate/022_create_info_request_events.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateInfoRequestEvents < ActiveRecord::Migration[4.2] # 2.0 +class CreateInfoRequestEvents < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :info_request_events do |t| t.column "info_request_id", :integer diff --git a/db/migrate/023_outgoing_message_last_sent_at.rb b/db/migrate/023_outgoing_message_last_sent_at.rb index 9d43446f87..c38b1fb052 100644 --- a/db/migrate/023_outgoing_message_last_sent_at.rb +++ b/db/migrate/023_outgoing_message_last_sent_at.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class OutgoingMessageLastSentAt < ActiveRecord::Migration[4.2] # 2.0 +class OutgoingMessageLastSentAt < ActiveRecord::Migration[4.2] # 2.0 def self.up rename_column(:outgoing_messages, :sent_at, :last_sent_at) end diff --git a/db/migrate/024_add_is_bounce_to_incoming_messages.rb b/db/migrate/024_add_is_bounce_to_incoming_messages.rb index e9ffb46aee..1eb0199c22 100644 --- a/db/migrate/024_add_is_bounce_to_incoming_messages.rb +++ b/db/migrate/024_add_is_bounce_to_incoming_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIsBounceToIncomingMessages < ActiveRecord::Migration[4.2] # 2.0 +class AddIsBounceToIncomingMessages < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :incoming_messages, :is_bounce, :boolean, :default => false IncomingMessage.update_all "is_bounce = 'f'" diff --git a/db/migrate/025_add_followup_to_outgoing_message.rb b/db/migrate/025_add_followup_to_outgoing_message.rb index 2fc906deff..83a5f561ee 100644 --- a/db/migrate/025_add_followup_to_outgoing_message.rb +++ b/db/migrate/025_add_followup_to_outgoing_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddFollowupToOutgoingMessage < ActiveRecord::Migration[4.2] # 2.0 +class AddFollowupToOutgoingMessage < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :outgoing_messages, :incoming_message_followup_id, :integer end diff --git a/db/migrate/026_add_many_null_constraints.rb b/db/migrate/026_add_many_null_constraints.rb index f531a56d20..ff6d5d72ca 100644 --- a/db/migrate/026_add_many_null_constraints.rb +++ b/db/migrate/026_add_many_null_constraints.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddManyNullConstraints < ActiveRecord::Migration[4.2] # 2.0 +class AddManyNullConstraints < ActiveRecord::Migration[4.2] # 2.0 def self.up change_column :users, :email, :string, :null => false change_column :users, :name, :string, :null => false diff --git a/db/migrate/027_change_classification_system.rb b/db/migrate/027_change_classification_system.rb index a2db0d47a0..aa0b84d57f 100644 --- a/db/migrate/027_change_classification_system.rb +++ b/db/migrate/027_change_classification_system.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ChangeClassificationSystem < ActiveRecord::Migration[4.2] # 2.0 +class ChangeClassificationSystem < ActiveRecord::Migration[4.2] # 2.0 def self.up remove_column :incoming_messages, :contains_information remove_column :incoming_messages, :user_classified diff --git a/db/migrate/028_give_incoming_messages_events.rb b/db/migrate/028_give_incoming_messages_events.rb index e8db139158..33f352fbfc 100644 --- a/db/migrate/028_give_incoming_messages_events.rb +++ b/db/migrate/028_give_incoming_messages_events.rb @@ -4,7 +4,7 @@ # validates_inclusion_of :described_state, :in => [ # Or do some nice hack in here to make it happen permanently :) -class GiveIncomingMessagesEvents < ActiveRecord::Migration[4.2] # 2.0 +class GiveIncomingMessagesEvents < ActiveRecord::Migration[4.2] # 2.0 def self.up ActiveRecord::Base.transaction do IncomingMessage.find_each do |incoming_message| diff --git a/db/migrate/029_add_describe_status_history.rb b/db/migrate/029_add_describe_status_history.rb index e221e535b8..9bc8d29df7 100644 --- a/db/migrate/029_add_describe_status_history.rb +++ b/db/migrate/029_add_describe_status_history.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDescribeStatusHistory < ActiveRecord::Migration[4.2] # 2.0 +class AddDescribeStatusHistory < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_request_events, :described_state, :string remove_column :info_requests, :described_last_incoming_message_id diff --git a/db/migrate/030_add_some_indices.rb b/db/migrate/030_add_some_indices.rb index 54700defe7..e96063e5c3 100644 --- a/db/migrate/030_add_some_indices.rb +++ b/db/migrate/030_add_some_indices.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddSomeIndices < ActiveRecord::Migration[4.2] # 2.0 +class AddSomeIndices < ActiveRecord::Migration[4.2] # 2.0 def self.up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" execute 'create index users_lower_email_index on users(lower(email))' diff --git a/db/migrate/031_add_indices_for_session_deletion.rb b/db/migrate/031_add_indices_for_session_deletion.rb index d4d2cee42d..56764501fb 100644 --- a/db/migrate/031_add_indices_for_session_deletion.rb +++ b/db/migrate/031_add_indices_for_session_deletion.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIndicesForSessionDeletion < ActiveRecord::Migration[4.2] # 2.0 +class AddIndicesForSessionDeletion < ActiveRecord::Migration[4.2] # 2.0 def self.up add_index :post_redirects, :updated_at end diff --git a/db/migrate/032_addforeignkeys.rb b/db/migrate/032_addforeignkeys.rb index dfc1935535..33604c3367 100644 --- a/db/migrate/032_addforeignkeys.rb +++ b/db/migrate/032_addforeignkeys.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class Addforeignkeys < ActiveRecord::Migration[4.2] # 2.0 +class Addforeignkeys < ActiveRecord::Migration[4.2] # 2.0 def self.up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" execute "ALTER TABLE incoming_messages ADD CONSTRAINT fk_incoming_messages_info_request FOREIGN KEY (info_request_id) REFERENCES info_requests(id)" diff --git a/db/migrate/033_add_prominence.rb b/db/migrate/033_add_prominence.rb index d4735178ac..7c108351bc 100644 --- a/db/migrate/033_add_prominence.rb +++ b/db/migrate/033_add_prominence.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddProminence < ActiveRecord::Migration[4.2] # 2.0 +class AddProminence < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_requests, :prominence, :string, :null => false, :default => 'normal' end diff --git a/db/migrate/034_run_solr_indexing.rb b/db/migrate/034_run_solr_indexing.rb index 59de1984f2..1cb95d037f 100644 --- a/db/migrate/034_run_solr_indexing.rb +++ b/db/migrate/034_run_solr_indexing.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RunSolrIndexing < ActiveRecord::Migration[4.2] # 2.0 +class RunSolrIndexing < ActiveRecord::Migration[4.2] # 2.0 def self.up # Not using SOLR yet after all #PublicBody.rebuild_solr_index diff --git a/db/migrate/035_track_overdue_alerts.rb b/db/migrate/035_track_overdue_alerts.rb index 8401f0dc08..35aeb5700f 100644 --- a/db/migrate/035_track_overdue_alerts.rb +++ b/db/migrate/035_track_overdue_alerts.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class TrackOverdueAlerts < ActiveRecord::Migration[4.2] # 2.0 +class TrackOverdueAlerts < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :user_info_request_sent_alerts do |t| t.column :user_id, :integer, :null => false diff --git a/db/migrate/036_add_public_body_tags.rb b/db/migrate/036_add_public_body_tags.rb index 8aee537502..0cd3cf6eb6 100644 --- a/db/migrate/036_add_public_body_tags.rb +++ b/db/migrate/036_add_public_body_tags.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPublicBodyTags < ActiveRecord::Migration[4.2] # 2.0 +class AddPublicBodyTags < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :public_body_tags do |t| t.column :public_body_id, :integer, :null => false diff --git a/db/migrate/037_add_url_name.rb b/db/migrate/037_add_url_name.rb index 9d1fad60c4..e3be63bc26 100644 --- a/db/migrate/037_add_url_name.rb +++ b/db/migrate/037_add_url_name.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUrlName < ActiveRecord::Migration[4.2] # 2.0 +class AddUrlName < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :public_bodies, :url_name, :text add_column :public_body_versions, :url_name, :text diff --git a/db/migrate/038_add_more_url_names.rb b/db/migrate/038_add_more_url_names.rb index 0f22426689..ebc5f25d09 100644 --- a/db/migrate/038_add_more_url_names.rb +++ b/db/migrate/038_add_more_url_names.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddMoreUrlNames < ActiveRecord::Migration[4.2] # 2.0 +class AddMoreUrlNames < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :users, :url_name, :text diff --git a/db/migrate/039_request_url_names.rb b/db/migrate/039_request_url_names.rb index 13c3e5e8d5..9cdb6eafae 100644 --- a/db/migrate/039_request_url_names.rb +++ b/db/migrate/039_request_url_names.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RequestUrlNames < ActiveRecord::Migration[4.2] # 2.0 +class RequestUrlNames < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_requests, :url_title, :text diff --git a/db/migrate/040_email_is_unique.rb b/db/migrate/040_email_is_unique.rb index d94b617071..30aff43151 100644 --- a/db/migrate/040_email_is_unique.rb +++ b/db/migrate/040_email_is_unique.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class EmailIsUnique < ActiveRecord::Migration[4.2] # 2.0 +class EmailIsUnique < ActiveRecord::Migration[4.2] # 2.0 def self.up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" execute "create unique index users_email_index on users (lower(email))" diff --git a/db/migrate/041_index_requests_with_solr.rb b/db/migrate/041_index_requests_with_solr.rb index 1317a6db68..55297c941b 100644 --- a/db/migrate/041_index_requests_with_solr.rb +++ b/db/migrate/041_index_requests_with_solr.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class IndexRequestsWithSolr < ActiveRecord::Migration[4.2] # 2.0 +class IndexRequestsWithSolr < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_requests, :solr_up_to_date, :boolean, :default => false, :null => false add_index :info_requests, :solr_up_to_date diff --git a/db/migrate/042_unique_user_urls.rb b/db/migrate/042_unique_user_urls.rb index 22a50876ff..2e12e1c473 100644 --- a/db/migrate/042_unique_user_urls.rb +++ b/db/migrate/042_unique_user_urls.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class UniqueUserUrls < ActiveRecord::Migration[4.2] # 2.0 +class UniqueUserUrls < ActiveRecord::Migration[4.2] # 2.0 def self.up # do last registered ones first, so the last ones get rubbish URLs User.order("id desc").each do |user| diff --git a/db/migrate/043_remove_complaint_email.rb b/db/migrate/043_remove_complaint_email.rb index 7e10cf0b97..7f4aeaf44f 100644 --- a/db/migrate/043_remove_complaint_email.rb +++ b/db/migrate/043_remove_complaint_email.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveComplaintEmail < ActiveRecord::Migration[4.2] # 2.0 +class RemoveComplaintEmail < ActiveRecord::Migration[4.2] # 2.0 def self.up remove_column :public_body_versions, :complaint_email remove_column :public_bodies, :complaint_email diff --git a/db/migrate/044_remove_is_bounce.rb b/db/migrate/044_remove_is_bounce.rb index 20752c6644..34e1439904 100644 --- a/db/migrate/044_remove_is_bounce.rb +++ b/db/migrate/044_remove_is_bounce.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveIsBounce < ActiveRecord::Migration[4.2] # 2.0 +class RemoveIsBounce < ActiveRecord::Migration[4.2] # 2.0 def self.up remove_column :incoming_messages, :is_bounce end diff --git a/db/migrate/045_add_circumstance_to_post_redirect.rb b/db/migrate/045_add_circumstance_to_post_redirect.rb index a095c7873c..dd78f9b11b 100644 --- a/db/migrate/045_add_circumstance_to_post_redirect.rb +++ b/db/migrate/045_add_circumstance_to_post_redirect.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCircumstanceToPostRedirect < ActiveRecord::Migration[4.2] # 2.0 +class AddCircumstanceToPostRedirect < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :post_redirects, :circumstance, :text, :default => "normal" PostRedirect.update_all "circumstance = 'normal'" diff --git a/db/migrate/046_add_last_event_id_to_alert_table.rb b/db/migrate/046_add_last_event_id_to_alert_table.rb index 3585c561f8..b9e33df2b8 100644 --- a/db/migrate/046_add_last_event_id_to_alert_table.rb +++ b/db/migrate/046_add_last_event_id_to_alert_table.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddLastEventIdToAlertTable < ActiveRecord::Migration[4.2] # 2.0 +class AddLastEventIdToAlertTable < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :user_info_request_sent_alerts, :info_request_event_id, :integer, :default => nil if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" diff --git a/db/migrate/047_add_calculated_state.rb b/db/migrate/047_add_calculated_state.rb index 3cb8d70ff4..5f5ba5fd26 100644 --- a/db/migrate/047_add_calculated_state.rb +++ b/db/migrate/047_add_calculated_state.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCalculatedState < ActiveRecord::Migration[4.2] # 2.0 +class AddCalculatedState < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_request_events, :calculated_state, :string, :default => nil end diff --git a/db/migrate/048_add_calculated_state_at.rb b/db/migrate/048_add_calculated_state_at.rb index 4888ab15e9..2e21c9e590 100644 --- a/db/migrate/048_add_calculated_state_at.rb +++ b/db/migrate/048_add_calculated_state_at.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCalculatedStateAt < ActiveRecord::Migration[4.2] # 2.0 +class AddCalculatedStateAt < ActiveRecord::Migration[4.2] # 2.0 def self.up # This is for use in RSS feeds add_column :info_request_events, :last_described_at, :datetime diff --git a/db/migrate/049_track_things.rb b/db/migrate/049_track_things.rb index 8fb91a6867..d2b7c5ec73 100644 --- a/db/migrate/049_track_things.rb +++ b/db/migrate/049_track_things.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class TrackThings < ActiveRecord::Migration[4.2] # 2.0 +class TrackThings < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :track_things do |t| t.column :tracking_user_id, :integer, :null => false diff --git a/db/migrate/050_improve_track_things.rb b/db/migrate/050_improve_track_things.rb index 2986e71ced..606fcc4623 100644 --- a/db/migrate/050_improve_track_things.rb +++ b/db/migrate/050_improve_track_things.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ImproveTrackThings < ActiveRecord::Migration[4.2] # 2.0 +class ImproveTrackThings < ActiveRecord::Migration[4.2] # 2.0 def self.up # SQLite at least needs a default for this add_column :track_things, :track_type, :string, :null => false, :default => "internal_error" diff --git a/db/migrate/051_add_track_things_unique_indices.rb b/db/migrate/051_add_track_things_unique_indices.rb index 11c212d7d3..379e7a6b40 100644 --- a/db/migrate/051_add_track_things_unique_indices.rb +++ b/db/migrate/051_add_track_things_unique_indices.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTrackThingsUniqueIndices < ActiveRecord::Migration[4.2] # 2.0 +class AddTrackThingsUniqueIndices < ActiveRecord::Migration[4.2] # 2.0 def self.up add_index :track_things, [:tracking_user_id, :track_query], :unique => true # GRRR - this index confuses Rails migrations, and it makes part of the index but not all diff --git a/db/migrate/052_include_event_foreign_references.rb b/db/migrate/052_include_event_foreign_references.rb index 9da4987939..bc4746820a 100644 --- a/db/migrate/052_include_event_foreign_references.rb +++ b/db/migrate/052_include_event_foreign_references.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class IncludeEventForeignReferences < ActiveRecord::Migration[4.2] # 2.0 +class IncludeEventForeignReferences < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_request_events, :incoming_message_id, :integer add_column :info_request_events, :outgoing_message_id, :integer diff --git a/db/migrate/053_acts_as_xapian_migration.rb b/db/migrate/053_acts_as_xapian_migration.rb index f1b0a39f91..0a499a8930 100644 --- a/db/migrate/053_acts_as_xapian_migration.rb +++ b/db/migrate/053_acts_as_xapian_migration.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ActsAsXapianMigration < ActiveRecord::Migration[4.2] # 2.0 +class ActsAsXapianMigration < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :acts_as_xapian_jobs do |t| t.column :model, :string, :null => false diff --git a/db/migrate/054_allow_longer_comments.rb b/db/migrate/054_allow_longer_comments.rb index a0eed4b8ed..3e27847387 100644 --- a/db/migrate/054_allow_longer_comments.rb +++ b/db/migrate/054_allow_longer_comments.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AllowLongerComments < ActiveRecord::Migration[4.2] # 2.0 +class AllowLongerComments < ActiveRecord::Migration[4.2] # 2.0 def self.up change_column :public_body_versions, :last_edit_comment, :text end diff --git a/db/migrate/055_stop_new_responses.rb b/db/migrate/055_stop_new_responses.rb index 31d8d05d42..7591da984a 100644 --- a/db/migrate/055_stop_new_responses.rb +++ b/db/migrate/055_stop_new_responses.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class StopNewResponses < ActiveRecord::Migration[4.2] # 2.0 +class StopNewResponses < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_requests, :stop_new_responses, :boolean, :default => false, :null => false end diff --git a/db/migrate/056_add_attachment_text.rb b/db/migrate/056_add_attachment_text.rb index a3de18beaf..5705752014 100644 --- a/db/migrate/056_add_attachment_text.rb +++ b/db/migrate/056_add_attachment_text.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddAttachmentText < ActiveRecord::Migration[4.2] # 2.0 +class AddAttachmentText < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :incoming_messages, :cached_attachment_text, :text end diff --git a/db/migrate/057_add_law_used.rb b/db/migrate/057_add_law_used.rb index 8f58c7640f..3d7d92ae55 100644 --- a/db/migrate/057_add_law_used.rb +++ b/db/migrate/057_add_law_used.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddLawUsed < ActiveRecord::Migration[4.2] # 2.0 +class AddLawUsed < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :info_requests, :law_used, :string, :null => false, :default => 'foi' end diff --git a/db/migrate/058_remove_sessions.rb b/db/migrate/058_remove_sessions.rb index a050bb62da..536cdd57da 100644 --- a/db/migrate/058_remove_sessions.rb +++ b/db/migrate/058_remove_sessions.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveSessions < ActiveRecord::Migration[4.2] # 2.0 +class RemoveSessions < ActiveRecord::Migration[4.2] # 2.0 def self.up drop_table :sessions end diff --git a/db/migrate/059_add_url_notes.rb b/db/migrate/059_add_url_notes.rb index 1537f4059e..2f85552319 100644 --- a/db/migrate/059_add_url_notes.rb +++ b/db/migrate/059_add_url_notes.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUrlNotes < ActiveRecord::Migration[4.2] # 2.0 +class AddUrlNotes < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :public_bodies, :home_page, :text, :null => false, :default => "" add_column :public_bodies, :notes, :text, :null => false, :default => "" diff --git a/db/migrate/060_add_cached_main_text.rb b/db/migrate/060_add_cached_main_text.rb index c15b00f336..42335a61b6 100644 --- a/db/migrate/060_add_cached_main_text.rb +++ b/db/migrate/060_add_cached_main_text.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCachedMainText < ActiveRecord::Migration[4.2] # 2.0 +class AddCachedMainText < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :incoming_messages, :cached_main_body_text, :text end diff --git a/db/migrate/061_include_responses_in_tracks.rb b/db/migrate/061_include_responses_in_tracks.rb index 35057beb0b..6321693501 100644 --- a/db/migrate/061_include_responses_in_tracks.rb +++ b/db/migrate/061_include_responses_in_tracks.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class IncludeResponsesInTracks < ActiveRecord::Migration[4.2] # 2.0 +class IncludeResponsesInTracks < ActiveRecord::Migration[4.2] # 2.0 def self.up TrackThing.update_all "track_query = replace(track_query, 'variety:sent ', '') where track_type in ('public_body_updates', 'user_updates')" end diff --git a/db/migrate/062_add_comments.rb b/db/migrate/062_add_comments.rb index 6e2e4aa1b7..9d3b0074e8 100644 --- a/db/migrate/062_add_comments.rb +++ b/db/migrate/062_add_comments.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddComments < ActiveRecord::Migration[4.2] # 2.0 +class AddComments < ActiveRecord::Migration[4.2] # 2.0 def self.up create_table :comments do |t| t.column :user_id, :integer, :null => false diff --git a/db/migrate/063_add_admin_users.rb b/db/migrate/063_add_admin_users.rb index 7a6a63f03c..22cfac2a6c 100644 --- a/db/migrate/063_add_admin_users.rb +++ b/db/migrate/063_add_admin_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddAdminUsers < ActiveRecord::Migration[4.2] # 2.0 +class AddAdminUsers < ActiveRecord::Migration[4.2] # 2.0 def self.up add_column :users, :admin_level, :string, :null => false, :default => 'none' end diff --git a/db/migrate/064_indices_for_annotations.rb b/db/migrate/064_indices_for_annotations.rb index 5d5726ce01..0e3bebc227 100644 --- a/db/migrate/064_indices_for_annotations.rb +++ b/db/migrate/064_indices_for_annotations.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class IndicesForAnnotations < ActiveRecord::Migration[4.2] # 2.0 +class IndicesForAnnotations < ActiveRecord::Migration[4.2] # 2.0 def self.up add_index :info_request_events, :created_at add_index :info_request_events, :info_request_id diff --git a/db/migrate/065_add_comments_to_user_track.rb b/db/migrate/065_add_comments_to_user_track.rb index 7bc0d3917d..23a268765c 100644 --- a/db/migrate/065_add_comments_to_user_track.rb +++ b/db/migrate/065_add_comments_to_user_track.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCommentsToUserTrack < ActiveRecord::Migration[4.2] # 2.1 +class AddCommentsToUserTrack < ActiveRecord::Migration[4.2] # 2.1 def self.up TrackThing.update_all "track_query = replace(track_query, 'variety:sent ', '') where track_type in ('public_body_updates', 'user_updates')" TrackThing.where(:track_type => 'user_updates').each do |track_thing| diff --git a/db/migrate/066_add_first_letter.rb b/db/migrate/066_add_first_letter.rb index 0a4c83a204..15b9237426 100644 --- a/db/migrate/066_add_first_letter.rb +++ b/db/migrate/066_add_first_letter.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddFirstLetter < ActiveRecord::Migration[4.2] # 2.1 +class AddFirstLetter < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :public_bodies, :first_letter, :string add_index :public_bodies, :first_letter diff --git a/db/migrate/067_factor_out_raw_email.rb b/db/migrate/067_factor_out_raw_email.rb index 86a0cae03e..98b91ffd27 100644 --- a/db/migrate/067_factor_out_raw_email.rb +++ b/db/migrate/067_factor_out_raw_email.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class FactorOutRawEmail < ActiveRecord::Migration[4.2] # 2.1 +class FactorOutRawEmail < ActiveRecord::Migration[4.2] # 2.1 def self.up create_table :raw_emails do |t| t.column :data, :text, :null => false diff --git a/db/migrate/068_add_censor_table.rb b/db/migrate/068_add_censor_table.rb index 1dc0f3e391..c8def38df0 100644 --- a/db/migrate/068_add_censor_table.rb +++ b/db/migrate/068_add_censor_table.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCensorTable < ActiveRecord::Migration[4.2] # 2.1 +class AddCensorTable < ActiveRecord::Migration[4.2] # 2.1 def self.up create_table :censor_rules do |t| t.column :info_request_id, :integer diff --git a/db/migrate/069_add_what_doing.rb b/db/migrate/069_add_what_doing.rb index 08d652947f..38e179f9d7 100644 --- a/db/migrate/069_add_what_doing.rb +++ b/db/migrate/069_add_what_doing.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddWhatDoing < ActiveRecord::Migration[4.2] # 2.1 +class AddWhatDoing < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :outgoing_messages, :what_doing, :string add_index :outgoing_messages, :what_doing diff --git a/db/migrate/070_sent_are_waiting_response.rb b/db/migrate/070_sent_are_waiting_response.rb index b8e7ffccbf..d9090e5468 100644 --- a/db/migrate/070_sent_are_waiting_response.rb +++ b/db/migrate/070_sent_are_waiting_response.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class SentAreWaitingResponse < ActiveRecord::Migration[4.2] # 2.1 +class SentAreWaitingResponse < ActiveRecord::Migration[4.2] # 2.1 def self.up InfoRequestEvent.update_all "described_state = 'waiting_response', calculated_state = 'waiting_response', last_described_at = created_at where event_type = 'sent'" end diff --git a/db/migrate/071_add_exim_log.rb b/db/migrate/071_add_exim_log.rb index dd51860d8a..05dbb0f050 100644 --- a/db/migrate/071_add_exim_log.rb +++ b/db/migrate/071_add_exim_log.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEximLog < ActiveRecord::Migration[4.2] # 2.1 +class AddEximLog < ActiveRecord::Migration[4.2] # 2.1 def self.up create_table :exim_logs do |t| t.column :exim_log_done_id, :integer diff --git a/db/migrate/072_add_publication_scheme.rb b/db/migrate/072_add_publication_scheme.rb index e16fe7ff47..e09f156978 100644 --- a/db/migrate/072_add_publication_scheme.rb +++ b/db/migrate/072_add_publication_scheme.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPublicationScheme < ActiveRecord::Migration[4.2] # 2.1 +class AddPublicationScheme < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :public_bodies, :publication_scheme, :text, :null => false, :default => "" add_column :public_body_versions, :publication_scheme, :text, :null => false, :default => "" diff --git a/db/migrate/073_add_ban_user.rb b/db/migrate/073_add_ban_user.rb index 9e3cfcc74b..181415b893 100644 --- a/db/migrate/073_add_ban_user.rb +++ b/db/migrate/073_add_ban_user.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddBanUser < ActiveRecord::Migration[4.2] # 2.1 +class AddBanUser < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :users, :ban_text, :text, :null => false, :default => "" end diff --git a/db/migrate/074_create_holidays.rb b/db/migrate/074_create_holidays.rb index 6f593c196f..228f5a6ead 100644 --- a/db/migrate/074_create_holidays.rb +++ b/db/migrate/074_create_holidays.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateHolidays < ActiveRecord::Migration[4.2] # 2.1 +class CreateHolidays < ActiveRecord::Migration[4.2] # 2.1 def self.up create_table :holidays do |t| t.column :day, :date diff --git a/db/migrate/075_add_charity_number.rb b/db/migrate/075_add_charity_number.rb index bd8367c15a..8a504a7f7c 100644 --- a/db/migrate/075_add_charity_number.rb +++ b/db/migrate/075_add_charity_number.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCharityNumber < ActiveRecord::Migration[4.2] # 2.1 +class AddCharityNumber < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :public_bodies, :charity_number, :text, :null => false, :default => "" add_column :public_body_versions, :charity_number, :text, :null => false, :default => "" diff --git a/db/migrate/076_add_indices.rb b/db/migrate/076_add_indices.rb index 79d3c1595d..9bfa5c9bdd 100644 --- a/db/migrate/076_add_indices.rb +++ b/db/migrate/076_add_indices.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIndices < ActiveRecord::Migration[4.2] # 2.1 +class AddIndices < ActiveRecord::Migration[4.2] # 2.1 def self.up add_index :track_things_sent_emails, :track_thing_id end diff --git a/db/migrate/077_add_exim_log_index.rb b/db/migrate/077_add_exim_log_index.rb index 9ce07a0a65..cd253a4976 100644 --- a/db/migrate/077_add_exim_log_index.rb +++ b/db/migrate/077_add_exim_log_index.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEximLogIndex < ActiveRecord::Migration[4.2] # 2.1 +class AddEximLogIndex < ActiveRecord::Migration[4.2] # 2.1 def self.up add_index :exim_logs, :exim_log_done_id end diff --git a/db/migrate/078_expand_stop_new_responses.rb b/db/migrate/078_expand_stop_new_responses.rb index c5ec910d5f..a335e13787 100644 --- a/db/migrate/078_expand_stop_new_responses.rb +++ b/db/migrate/078_expand_stop_new_responses.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ExpandStopNewResponses < ActiveRecord::Migration[4.2] # 2.1 +class ExpandStopNewResponses < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :info_requests, :allow_new_responses_from, :string InfoRequest.update_all "allow_new_responses_from = 'anybody'" diff --git a/db/migrate/079_add_profile_photo.rb b/db/migrate/079_add_profile_photo.rb index 6024bb243e..9bb0f58f1f 100644 --- a/db/migrate/079_add_profile_photo.rb +++ b/db/migrate/079_add_profile_photo.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddProfilePhoto < ActiveRecord::Migration[4.2] # 2.1 +class AddProfilePhoto < ActiveRecord::Migration[4.2] # 2.1 def self.up create_table :profile_photos do |t| t.column :data, :binary, :null => false diff --git a/db/migrate/080_cache_only_clipped_attachment_text.rb b/db/migrate/080_cache_only_clipped_attachment_text.rb index 50a4de6815..6cf4edd04d 100644 --- a/db/migrate/080_cache_only_clipped_attachment_text.rb +++ b/db/migrate/080_cache_only_clipped_attachment_text.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CacheOnlyClippedAttachmentText < ActiveRecord::Migration[4.2] # 2.1 +class CacheOnlyClippedAttachmentText < ActiveRecord::Migration[4.2] # 2.1 def self.up remove_column :incoming_messages, :cached_attachment_text add_column :incoming_messages, :cached_attachment_text_clipped, :text diff --git a/db/migrate/081_add_event_prominence.rb b/db/migrate/081_add_event_prominence.rb index 549c28e7fc..f749b1603e 100644 --- a/db/migrate/081_add_event_prominence.rb +++ b/db/migrate/081_add_event_prominence.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEventProminence < ActiveRecord::Migration[4.2] # 2.1 +class AddEventProminence < ActiveRecord::Migration[4.2] # 2.1 def self.up add_column :info_request_events, :prominence, :string, :null => false, :default => 'normal' end diff --git a/db/migrate/082_change_raw_email_to_binary.rb b/db/migrate/082_change_raw_email_to_binary.rb index e9ff2823a8..a91263440e 100644 --- a/db/migrate/082_change_raw_email_to_binary.rb +++ b/db/migrate/082_change_raw_email_to_binary.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ChangeRawEmailToBinary < ActiveRecord::Migration[4.2] # 2.1 +class ChangeRawEmailToBinary < ActiveRecord::Migration[4.2] # 2.1 def self.up change_column :raw_emails, :data, :text, :null => true # allow null rename_column :raw_emails, :data, :data_text diff --git a/db/migrate/083_add_indices_track_sent.rb b/db/migrate/083_add_indices_track_sent.rb index 907331ba5f..c6528cc248 100644 --- a/db/migrate/083_add_indices_track_sent.rb +++ b/db/migrate/083_add_indices_track_sent.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIndicesTrackSent < ActiveRecord::Migration[4.2] # 2.3 +class AddIndicesTrackSent < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :track_things_sent_emails, :created_at end diff --git a/db/migrate/084_alter_profile_photo.rb b/db/migrate/084_alter_profile_photo.rb index e8b55a6724..a3b518d4e3 100644 --- a/db/migrate/084_alter_profile_photo.rb +++ b/db/migrate/084_alter_profile_photo.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AlterProfilePhoto < ActiveRecord::Migration[4.2] # 2.3 +class AlterProfilePhoto < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :users, :profile_photo_id end diff --git a/db/migrate/085_draft_profile_photo.rb b/db/migrate/085_draft_profile_photo.rb index 10fc078cef..a0538874df 100644 --- a/db/migrate/085_draft_profile_photo.rb +++ b/db/migrate/085_draft_profile_photo.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class DraftProfilePhoto < ActiveRecord::Migration[4.2] # 2.3 +class DraftProfilePhoto < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :profile_photos, :draft, :boolean, :default => false, :null => false end diff --git a/db/migrate/086_allow_null_profile_photo_user.rb b/db/migrate/086_allow_null_profile_photo_user.rb index bac12e4148..fa6658b7ea 100644 --- a/db/migrate/086_allow_null_profile_photo_user.rb +++ b/db/migrate/086_allow_null_profile_photo_user.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AllowNullProfilePhotoUser < ActiveRecord::Migration[4.2] # 2.3 +class AllowNullProfilePhotoUser < ActiveRecord::Migration[4.2] # 2.3 def self.up change_column :profile_photos, :user_id, :integer, :null => true end diff --git a/db/migrate/087_add_about_me.rb b/db/migrate/087_add_about_me.rb index 7096b5fe1f..ecf317c18b 100644 --- a/db/migrate/087_add_about_me.rb +++ b/db/migrate/087_add_about_me.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddAboutMe < ActiveRecord::Migration[4.2] # 2.3 +class AddAboutMe < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :users, :about_me, :text, :null => false, :default => "" end diff --git a/db/migrate/088_public_body_machine_tags.rb b/db/migrate/088_public_body_machine_tags.rb index b992408e80..92231338c8 100644 --- a/db/migrate/088_public_body_machine_tags.rb +++ b/db/migrate/088_public_body_machine_tags.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class PublicBodyMachineTags < ActiveRecord::Migration[4.2] # 2.3 +class PublicBodyMachineTags < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :public_body_tags, :value, :text diff --git a/db/migrate/089_remove_charity_number.rb b/db/migrate/089_remove_charity_number.rb index 498844a57b..793bbb40f7 100644 --- a/db/migrate/089_remove_charity_number.rb +++ b/db/migrate/089_remove_charity_number.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveCharityNumber < ActiveRecord::Migration[4.2] # 2.3 +class RemoveCharityNumber < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :public_bodies, :charity_number end diff --git a/db/migrate/090_remove_tag_uniqueness.rb b/db/migrate/090_remove_tag_uniqueness.rb index 5d905caf9b..39800b5914 100644 --- a/db/migrate/090_remove_tag_uniqueness.rb +++ b/db/migrate/090_remove_tag_uniqueness.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveTagUniqueness < ActiveRecord::Migration[4.2] # 2.3 +class RemoveTagUniqueness < ActiveRecord::Migration[4.2] # 2.3 def self.up # MySQL cannot index text blobs like this # TODO: perhaps should change :name/:value to be a :string diff --git a/db/migrate/091_add_censor_rules_indices.rb b/db/migrate/091_add_censor_rules_indices.rb index 9a7dfe4e82..43a553567c 100644 --- a/db/migrate/091_add_censor_rules_indices.rb +++ b/db/migrate/091_add_censor_rules_indices.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCensorRulesIndices < ActiveRecord::Migration[4.2] # 2.3 +class AddCensorRulesIndices < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :censor_rules, :info_request_id add_index :censor_rules, :user_id diff --git a/db/migrate/092_cache_only_marked_body_text.rb b/db/migrate/092_cache_only_marked_body_text.rb index 2a65365f11..36d56da0de 100644 --- a/db/migrate/092_cache_only_marked_body_text.rb +++ b/db/migrate/092_cache_only_marked_body_text.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CacheOnlyMarkedBodyText < ActiveRecord::Migration[4.2] # 2.3 +class CacheOnlyMarkedBodyText < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :incoming_messages, :cached_main_body_text add_column :incoming_messages, :cached_main_body_text_folded, :text diff --git a/db/migrate/093_move_to_has_tag_string.rb b/db/migrate/093_move_to_has_tag_string.rb index 2f639d5d83..a494d3ac28 100644 --- a/db/migrate/093_move_to_has_tag_string.rb +++ b/db/migrate/093_move_to_has_tag_string.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class MoveToHasTagString < ActiveRecord::Migration[4.2] # 2.3 +class MoveToHasTagString < ActiveRecord::Migration[4.2] # 2.3 def self.up rename_table :public_body_tags, :has_tag_string_tags diff --git a/db/migrate/094_remove_old_tags_foreign_key.rb b/db/migrate/094_remove_old_tags_foreign_key.rb index 2d9bd784cc..6c61f639b7 100644 --- a/db/migrate/094_remove_old_tags_foreign_key.rb +++ b/db/migrate/094_remove_old_tags_foreign_key.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveOldTagsForeignKey < ActiveRecord::Migration[4.2] # 2.3 +class RemoveOldTagsForeignKey < ActiveRecord::Migration[4.2] # 2.3 def self.up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" execute "ALTER TABLE has_tag_string_tags DROP CONSTRAINT fk_public_body_tags_public_body" diff --git a/db/migrate/095_add_post_redirect_user_index.rb b/db/migrate/095_add_post_redirect_user_index.rb index dea5230ee9..22508a4fdc 100644 --- a/db/migrate/095_add_post_redirect_user_index.rb +++ b/db/migrate/095_add_post_redirect_user_index.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPostRedirectUserIndex < ActiveRecord::Migration[4.2] # 2.3 +class AddPostRedirectUserIndex < ActiveRecord::Migration[4.2] # 2.3 # This index is for admin interface def self.up diff --git a/db/migrate/096_create_translation_tables.rb b/db/migrate/096_create_translation_tables.rb index 1769ea59f5..e1bea1dcb1 100644 --- a/db/migrate/096_create_translation_tables.rb +++ b/db/migrate/096_create_translation_tables.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateTranslationTables < ActiveRecord::Migration[4.2] # 2.3 +class CreateTranslationTables < ActiveRecord::Migration[4.2] # 2.3 def self.up fields = { :name => :text, :short_name => :text, diff --git a/db/migrate/097_add_comment_locale.rb b/db/migrate/097_add_comment_locale.rb index 2b03bcf62b..45c43c1694 100644 --- a/db/migrate/097_add_comment_locale.rb +++ b/db/migrate/097_add_comment_locale.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCommentLocale < ActiveRecord::Migration[4.2] # 2.3 +class AddCommentLocale < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :comments, :locale, :text, :null => false, :default => "" end diff --git a/db/migrate/098_fix_public_body_translations.rb b/db/migrate/098_fix_public_body_translations.rb index f0b5d8f996..1b326aa995 100644 --- a/db/migrate/098_fix_public_body_translations.rb +++ b/db/migrate/098_fix_public_body_translations.rb @@ -8,7 +8,7 @@ # Note that the "update ... from" syntax is a Postgres # extension to SQL. -class FixPublicBodyTranslations < ActiveRecord::Migration[4.2] # 2.3 +class FixPublicBodyTranslations < ActiveRecord::Migration[4.2] # 2.3 def self.up execute <<-SQL update public_body_translations diff --git a/db/migrate/099_move_raw_email_to_filesystem.rb b/db/migrate/099_move_raw_email_to_filesystem.rb index d9e680276e..56e195147c 100644 --- a/db/migrate/099_move_raw_email_to_filesystem.rb +++ b/db/migrate/099_move_raw_email_to_filesystem.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class MoveRawEmailToFilesystem < ActiveRecord::Migration[4.2] # 2.3 +class MoveRawEmailToFilesystem < ActiveRecord::Migration[4.2] # 2.3 def self.up RawEmail.find_each(:batch_size => 10) do |raw_email| if !File.exists?(raw_email.filepath) diff --git a/db/migrate/100_remove_redundant_raw_email_columns.rb b/db/migrate/100_remove_redundant_raw_email_columns.rb index 304e2ca35c..9acc2d8cb5 100644 --- a/db/migrate/100_remove_redundant_raw_email_columns.rb +++ b/db/migrate/100_remove_redundant_raw_email_columns.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveRedundantRawEmailColumns < ActiveRecord::Migration[4.2] # 2.3 +class RemoveRedundantRawEmailColumns < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :raw_emails, :data_text remove_column :raw_emails, :data_binary diff --git a/db/migrate/101_add_hash_to_info_request.rb b/db/migrate/101_add_hash_to_info_request.rb index cd77c3d451..7c12a5f009 100644 --- a/db/migrate/101_add_hash_to_info_request.rb +++ b/db/migrate/101_add_hash_to_info_request.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- require 'digest/sha1' -class AddHashToInfoRequest < ActiveRecord::Migration[4.2] # 2.3 +class AddHashToInfoRequest < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :info_requests, :idhash, :string diff --git a/db/migrate/102_add_locale_to_users.rb b/db/migrate/102_add_locale_to_users.rb index 99a49a7f8d..4ee096ae97 100644 --- a/db/migrate/102_add_locale_to_users.rb +++ b/db/migrate/102_add_locale_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddLocaleToUsers < ActiveRecord::Migration[4.2] # 2.3 +class AddLocaleToUsers < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :users, :locale, :string end diff --git a/db/migrate/103_add_user_bounce_columns.rb b/db/migrate/103_add_user_bounce_columns.rb index 563582333d..c4ac356ca6 100644 --- a/db/migrate/103_add_user_bounce_columns.rb +++ b/db/migrate/103_add_user_bounce_columns.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- require 'digest/sha1' -class AddUserBounceColumns < ActiveRecord::Migration[4.2] # 2.3 +class AddUserBounceColumns < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :users, :email_bounced_at, :datetime add_column :users, :email_bounce_message, :text, :default => "", :null => false diff --git a/db/migrate/104_create_foi_attachments.rb b/db/migrate/104_create_foi_attachments.rb index c55511aaca..fe050070f4 100644 --- a/db/migrate/104_create_foi_attachments.rb +++ b/db/migrate/104_create_foi_attachments.rb @@ -1,6 +1,6 @@ # -*- encoding : utf-8 -*- -class CreateFoiAttachments < ActiveRecord::Migration[4.2] # 2.3 +class CreateFoiAttachments < ActiveRecord::Migration[4.2] # 2.3 def self.up create_table :foi_attachments do |t| t.column :content_type, :text diff --git a/db/migrate/105_extend_incoming_message.rb b/db/migrate/105_extend_incoming_message.rb index 8a3eb19f6f..8adf4b5422 100644 --- a/db/migrate/105_extend_incoming_message.rb +++ b/db/migrate/105_extend_incoming_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ExtendIncomingMessage < ActiveRecord::Migration[4.2] # 2.3 +class ExtendIncomingMessage < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :incoming_messages, :sent_at, :time add_column :incoming_messages, :subject, :text diff --git a/db/migrate/106_add_hex_digest_to_foi_attachment.rb b/db/migrate/106_add_hex_digest_to_foi_attachment.rb index 48e7657048..52a8963c57 100644 --- a/db/migrate/106_add_hex_digest_to_foi_attachment.rb +++ b/db/migrate/106_add_hex_digest_to_foi_attachment.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddHexDigestToFoiAttachment < ActiveRecord::Migration[4.2] # 2.3 +class AddHexDigestToFoiAttachment < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :foi_attachments, :hexdigest, :string, :limit => 32 end diff --git a/db/migrate/107_add_date_parsed_field_to_incoming_message.rb b/db/migrate/107_add_date_parsed_field_to_incoming_message.rb index c4ad0e0df7..e425280748 100644 --- a/db/migrate/107_add_date_parsed_field_to_incoming_message.rb +++ b/db/migrate/107_add_date_parsed_field_to_incoming_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDateParsedFieldToIncomingMessage < ActiveRecord::Migration[4.2] # 2.3 +class AddDateParsedFieldToIncomingMessage < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :incoming_messages, :last_parsed, :datetime end diff --git a/db/migrate/108_change_safe_mail_from_to_mail_from.rb b/db/migrate/108_change_safe_mail_from_to_mail_from.rb index 6ee2be2d19..a81922f803 100644 --- a/db/migrate/108_change_safe_mail_from_to_mail_from.rb +++ b/db/migrate/108_change_safe_mail_from_to_mail_from.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ChangeSafeMailFromToMailFrom < ActiveRecord::Migration[4.2] # 2.3 +class ChangeSafeMailFromToMailFrom < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :incoming_messages, :safe_mail_from add_column :incoming_messages, :mail_from, :text diff --git a/db/migrate/109_change_sent_at_to_datetime.rb b/db/migrate/109_change_sent_at_to_datetime.rb index 27f4b773c3..0e6fea0bcd 100644 --- a/db/migrate/109_change_sent_at_to_datetime.rb +++ b/db/migrate/109_change_sent_at_to_datetime.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class ChangeSentAtToDatetime < ActiveRecord::Migration[4.2] # 2.3 +class ChangeSentAtToDatetime < ActiveRecord::Migration[4.2] # 2.3 def self.up remove_column :incoming_messages, :sent_at add_column :incoming_messages, :sent_at, :timestamp diff --git a/db/migrate/110_add_user_no_limit.rb b/db/migrate/110_add_user_no_limit.rb index a05b5f177f..c3fd8ed9b0 100644 --- a/db/migrate/110_add_user_no_limit.rb +++ b/db/migrate/110_add_user_no_limit.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- require 'digest/sha1' -class AddUserNoLimit < ActiveRecord::Migration[4.2] # 2.3 +class AddUserNoLimit < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :users, :no_limit, :boolean, :default => false, :null => false end diff --git a/db/migrate/111_create_purge_requests.rb b/db/migrate/111_create_purge_requests.rb index c5e23eec5a..a01b58a0b3 100644 --- a/db/migrate/111_create_purge_requests.rb +++ b/db/migrate/111_create_purge_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreatePurgeRequests < ActiveRecord::Migration[4.2] # 2.3 +class CreatePurgeRequests < ActiveRecord::Migration[4.2] # 2.3 def self.up create_table :purge_requests do |t| t.column :url, :string diff --git a/db/migrate/112_add_api_key_to_public_bodies.rb b/db/migrate/112_add_api_key_to_public_bodies.rb index 5192482d8d..7d7691246b 100644 --- a/db/migrate/112_add_api_key_to_public_bodies.rb +++ b/db/migrate/112_add_api_key_to_public_bodies.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- require "securerandom" -class AddApiKeyToPublicBodies < ActiveRecord::Migration[4.2] # 2.3 +class AddApiKeyToPublicBodies < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :public_bodies, :api_key, :string diff --git a/db/migrate/113_add_external_fields_to_info_requests.rb b/db/migrate/113_add_external_fields_to_info_requests.rb index dfc47f367c..ec33462234 100644 --- a/db/migrate/113_add_external_fields_to_info_requests.rb +++ b/db/migrate/113_add_external_fields_to_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddExternalFieldsToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 +class AddExternalFieldsToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 def self.up change_column_null :info_requests, :user_id, true add_column :info_requests, :external_user_name, :string, :null => true diff --git a/db/migrate/114_add_attention_requested_flag_to_info_requests.rb b/db/migrate/114_add_attention_requested_flag_to_info_requests.rb index afd110a4cf..5447d2df8d 100644 --- a/db/migrate/114_add_attention_requested_flag_to_info_requests.rb +++ b/db/migrate/114_add_attention_requested_flag_to_info_requests.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- require 'digest/sha1' -class AddAttentionRequestedFlagToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 +class AddAttentionRequestedFlagToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :info_requests, :attention_requested, :boolean, :default => false end diff --git a/db/migrate/115_add_receive_email_alerts_to_user.rb b/db/migrate/115_add_receive_email_alerts_to_user.rb index 4792debef8..db1fb30d34 100644 --- a/db/migrate/115_add_receive_email_alerts_to_user.rb +++ b/db/migrate/115_add_receive_email_alerts_to_user.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddReceiveEmailAlertsToUser < ActiveRecord::Migration[4.2] # 2.3 +class AddReceiveEmailAlertsToUser < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :users, :receive_email_alerts, :boolean, :default => true, :null => false end diff --git a/db/migrate/116_add_censor_rule_regexp.rb b/db/migrate/116_add_censor_rule_regexp.rb index c1c5e0a1a3..3f1b2ba75a 100644 --- a/db/migrate/116_add_censor_rule_regexp.rb +++ b/db/migrate/116_add_censor_rule_regexp.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCensorRuleRegexp < ActiveRecord::Migration[4.2] # 2.3 +class AddCensorRuleRegexp < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :censor_rules, :regexp, :boolean end diff --git a/db/migrate/117_create_sessions.rb b/db/migrate/117_create_sessions.rb index 21a6c6cb5c..d3de07ba00 100644 --- a/db/migrate/117_create_sessions.rb +++ b/db/migrate/117_create_sessions.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateSessions < ActiveRecord::Migration[4.2] # 2.3 +class CreateSessions < ActiveRecord::Migration[4.2] # 2.3 def self.up create_table :sessions do |t| t.string :session_id, :null => false diff --git a/db/migrate/118_remove_sessions_again.rb b/db/migrate/118_remove_sessions_again.rb index 620b6a1a03..67dbf8a510 100644 --- a/db/migrate/118_remove_sessions_again.rb +++ b/db/migrate/118_remove_sessions_again.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveSessionsAgain < ActiveRecord::Migration[4.2] # 2.3 +class RemoveSessionsAgain < ActiveRecord::Migration[4.2] # 2.3 def self.up drop_table :sessions end diff --git a/db/migrate/20120822145640_correct_external_request_constraint.rb b/db/migrate/20120822145640_correct_external_request_constraint.rb index 4d8256355b..c8e658b651 100644 --- a/db/migrate/20120822145640_correct_external_request_constraint.rb +++ b/db/migrate/20120822145640_correct_external_request_constraint.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CorrectExternalRequestConstraint < ActiveRecord::Migration[4.2] # 2.3 +class CorrectExternalRequestConstraint < ActiveRecord::Migration[4.2] # 2.3 def self.up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" execute "ALTER TABLE info_requests DROP CONSTRAINT info_requests_external_ck" diff --git a/db/migrate/20120910153022_create_request_classifications.rb b/db/migrate/20120910153022_create_request_classifications.rb index 4edce435ad..a658fde34b 100644 --- a/db/migrate/20120910153022_create_request_classifications.rb +++ b/db/migrate/20120910153022_create_request_classifications.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateRequestClassifications < ActiveRecord::Migration[4.2] # 2.3 +class CreateRequestClassifications < ActiveRecord::Migration[4.2] # 2.3 def self.up create_table :request_classifications do |t| t.integer :user_id diff --git a/db/migrate/20120912111713_add_raw_email_index_to_incoming_messages.rb b/db/migrate/20120912111713_add_raw_email_index_to_incoming_messages.rb index cf8fdb4956..9aac65f492 100644 --- a/db/migrate/20120912111713_add_raw_email_index_to_incoming_messages.rb +++ b/db/migrate/20120912111713_add_raw_email_index_to_incoming_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddRawEmailIndexToIncomingMessages < ActiveRecord::Migration[4.2] # 2.3 +class AddRawEmailIndexToIncomingMessages < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :incoming_messages, :raw_email_id end diff --git a/db/migrate/20120912112036_add_info_request_id_index_to_exim_logs.rb b/db/migrate/20120912112036_add_info_request_id_index_to_exim_logs.rb index 220e392f42..63cb2b144c 100644 --- a/db/migrate/20120912112036_add_info_request_id_index_to_exim_logs.rb +++ b/db/migrate/20120912112036_add_info_request_id_index_to_exim_logs.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestIdIndexToEximLogs < ActiveRecord::Migration[4.2] # 2.3 +class AddInfoRequestIdIndexToEximLogs < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :exim_logs, :info_request_id end diff --git a/db/migrate/20120912112312_add_info_request_id_index_to_incoming_and_outgoing_messages.rb b/db/migrate/20120912112312_add_info_request_id_index_to_incoming_and_outgoing_messages.rb index d80a3f8f6c..d76067002c 100644 --- a/db/migrate/20120912112312_add_info_request_id_index_to_incoming_and_outgoing_messages.rb +++ b/db/migrate/20120912112312_add_info_request_id_index_to_incoming_and_outgoing_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestIdIndexToIncomingAndOutgoingMessages < ActiveRecord::Migration[4.2] # 2.3 +class AddInfoRequestIdIndexToIncomingAndOutgoingMessages < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :incoming_messages, :info_request_id add_index :outgoing_messages, :info_request_id diff --git a/db/migrate/20120912112655_add_incoming_message_id_index_to_foi_attachments.rb b/db/migrate/20120912112655_add_incoming_message_id_index_to_foi_attachments.rb index 67b4c51527..8797fddc6c 100644 --- a/db/migrate/20120912112655_add_incoming_message_id_index_to_foi_attachments.rb +++ b/db/migrate/20120912112655_add_incoming_message_id_index_to_foi_attachments.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIncomingMessageIdIndexToFoiAttachments < ActiveRecord::Migration[4.2] # 2.3 +class AddIncomingMessageIdIndexToFoiAttachments < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :foi_attachments, :incoming_message_id end diff --git a/db/migrate/20120912113004_add_indexes_to_info_request_events.rb b/db/migrate/20120912113004_add_indexes_to_info_request_events.rb index 6774914636..b650376d5d 100644 --- a/db/migrate/20120912113004_add_indexes_to_info_request_events.rb +++ b/db/migrate/20120912113004_add_indexes_to_info_request_events.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIndexesToInfoRequestEvents < ActiveRecord::Migration[4.2] # 2.3 +class AddIndexesToInfoRequestEvents < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :info_request_events, :incoming_message_id add_index :info_request_events, :outgoing_message_id diff --git a/db/migrate/20120912113720_add_public_body_index_to_info_requests.rb b/db/migrate/20120912113720_add_public_body_index_to_info_requests.rb index c9ab9233cf..27ce6696c6 100644 --- a/db/migrate/20120912113720_add_public_body_index_to_info_requests.rb +++ b/db/migrate/20120912113720_add_public_body_index_to_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPublicBodyIndexToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 +class AddPublicBodyIndexToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :info_requests, :public_body_id end diff --git a/db/migrate/20120912114022_add_user_index_to_info_requests.rb b/db/migrate/20120912114022_add_user_index_to_info_requests.rb index a14cda1aa9..408a6c6add 100644 --- a/db/migrate/20120912114022_add_user_index_to_info_requests.rb +++ b/db/migrate/20120912114022_add_user_index_to_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUserIndexToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 +class AddUserIndexToInfoRequests < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :info_requests, :user_id end diff --git a/db/migrate/20120912170035_add_info_requests_count_to_public_bodies.rb b/db/migrate/20120912170035_add_info_requests_count_to_public_bodies.rb index 1b97f07206..216616a922 100644 --- a/db/migrate/20120912170035_add_info_requests_count_to_public_bodies.rb +++ b/db/migrate/20120912170035_add_info_requests_count_to_public_bodies.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestsCountToPublicBodies < ActiveRecord::Migration[4.2] # 2.3 +class AddInfoRequestsCountToPublicBodies < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :public_bodies, :info_requests_count, :integer, :null => false, :default => 0 diff --git a/db/migrate/20120913074940_add_incoming_message_index_to_outgoing_messages.rb b/db/migrate/20120913074940_add_incoming_message_index_to_outgoing_messages.rb index 6d3707c589..ad831d27a5 100644 --- a/db/migrate/20120913074940_add_incoming_message_index_to_outgoing_messages.rb +++ b/db/migrate/20120913074940_add_incoming_message_index_to_outgoing_messages.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIncomingMessageIndexToOutgoingMessages < ActiveRecord::Migration[4.2] # 2.3 +class AddIncomingMessageIndexToOutgoingMessages < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :outgoing_messages, :incoming_message_followup_id end diff --git a/db/migrate/20120913080807_add_info_request_event_index_to_track_things_sent_emails.rb b/db/migrate/20120913080807_add_info_request_event_index_to_track_things_sent_emails.rb index f227e24939..69eeb1e9e0 100644 --- a/db/migrate/20120913080807_add_info_request_event_index_to_track_things_sent_emails.rb +++ b/db/migrate/20120913080807_add_info_request_event_index_to_track_things_sent_emails.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestEventIndexToTrackThingsSentEmails < ActiveRecord::Migration[4.2] # 2.3 +class AddInfoRequestEventIndexToTrackThingsSentEmails < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :track_things_sent_emails, :info_request_event_id end diff --git a/db/migrate/20120913081136_add_info_request_event_index_to_user_info_request_sent_alerts.rb b/db/migrate/20120913081136_add_info_request_event_index_to_user_info_request_sent_alerts.rb index 8e833d10da..1bdb4fa9f4 100644 --- a/db/migrate/20120913081136_add_info_request_event_index_to_user_info_request_sent_alerts.rb +++ b/db/migrate/20120913081136_add_info_request_event_index_to_user_info_request_sent_alerts.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestEventIndexToUserInfoRequestSentAlerts < ActiveRecord::Migration[4.2] # 2.3 +class AddInfoRequestEventIndexToUserInfoRequestSentAlerts < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :user_info_request_sent_alerts, :info_request_event_id end diff --git a/db/migrate/20120913135745_add_updated_at_index_to_public_body_versions.rb b/db/migrate/20120913135745_add_updated_at_index_to_public_body_versions.rb index 9a0d41f5ef..eadc2d13c5 100644 --- a/db/migrate/20120913135745_add_updated_at_index_to_public_body_versions.rb +++ b/db/migrate/20120913135745_add_updated_at_index_to_public_body_versions.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUpdatedAtIndexToPublicBodyVersions < ActiveRecord::Migration[4.2] # 2.3 +class AddUpdatedAtIndexToPublicBodyVersions < ActiveRecord::Migration[4.2] # 2.3 def self.up add_index :public_body_versions, :updated_at end diff --git a/db/migrate/20120919140404_add_comments_allowed_to_info_request.rb b/db/migrate/20120919140404_add_comments_allowed_to_info_request.rb index 68fa55c757..07615a8b54 100644 --- a/db/migrate/20120919140404_add_comments_allowed_to_info_request.rb +++ b/db/migrate/20120919140404_add_comments_allowed_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCommentsAllowedToInfoRequest < ActiveRecord::Migration[4.2] # 2.3 +class AddCommentsAllowedToInfoRequest < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :info_requests, :comments_allowed, :boolean, :null => false, :default => true end diff --git a/db/migrate/20121010214348_rename_exim_log_tables.rb b/db/migrate/20121010214348_rename_exim_log_tables.rb index f69dd8e3f1..99bf1c6e99 100644 --- a/db/migrate/20121010214348_rename_exim_log_tables.rb +++ b/db/migrate/20121010214348_rename_exim_log_tables.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RenameEximLogTables < ActiveRecord::Migration[4.2] # 2.3 +class RenameEximLogTables < ActiveRecord::Migration[4.2] # 2.3 def self.up rename_table :exim_logs, :mail_server_logs rename_table :exim_log_dones, :mail_server_log_dones diff --git a/db/migrate/20121022031914_add_disclosure_log.rb b/db/migrate/20121022031914_add_disclosure_log.rb index 80c0b48550..892f1d7f07 100644 --- a/db/migrate/20121022031914_add_disclosure_log.rb +++ b/db/migrate/20121022031914_add_disclosure_log.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDisclosureLog < ActiveRecord::Migration[4.2] # 2.3 +class AddDisclosureLog < ActiveRecord::Migration[4.2] # 2.3 def self.up add_column :public_bodies, :disclosure_log, :text, :null => false, :default => "" add_column :public_body_versions, :disclosure_log, :text, :null => false, :default => "" diff --git a/db/migrate/20130731142632_remove_prominence_from_info_request_event.rb b/db/migrate/20130731142632_remove_prominence_from_info_request_event.rb index df16a4b489..c40aca4892 100644 --- a/db/migrate/20130731142632_remove_prominence_from_info_request_event.rb +++ b/db/migrate/20130731142632_remove_prominence_from_info_request_event.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveProminenceFromInfoRequestEvent < ActiveRecord::Migration[4.2] # 3.1 +class RemoveProminenceFromInfoRequestEvent < ActiveRecord::Migration[4.2] # 3.1 def up remove_column :info_request_events, :prominence end diff --git a/db/migrate/20130731145325_add_prominence_to_incoming_message.rb b/db/migrate/20130731145325_add_prominence_to_incoming_message.rb index 7da02144fe..0a877c5d0c 100644 --- a/db/migrate/20130731145325_add_prominence_to_incoming_message.rb +++ b/db/migrate/20130731145325_add_prominence_to_incoming_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddProminenceToIncomingMessage < ActiveRecord::Migration[4.2] # 3.1 +class AddProminenceToIncomingMessage < ActiveRecord::Migration[4.2] # 3.1 def change add_column :incoming_messages, :prominence, :string, :null => false, :default => 'normal' end diff --git a/db/migrate/20130801154033_add_prominence_reason_to_incoming_message.rb b/db/migrate/20130801154033_add_prominence_reason_to_incoming_message.rb index 799bb9eb9b..14b695589e 100644 --- a/db/migrate/20130801154033_add_prominence_reason_to_incoming_message.rb +++ b/db/migrate/20130801154033_add_prominence_reason_to_incoming_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddProminenceReasonToIncomingMessage < ActiveRecord::Migration[4.2] # 3.1 +class AddProminenceReasonToIncomingMessage < ActiveRecord::Migration[4.2] # 3.1 def change add_column :incoming_messages, :prominence_reason, :text end diff --git a/db/migrate/20130816150110_add_statistics_to_public_body.rb b/db/migrate/20130816150110_add_statistics_to_public_body.rb index e2d9ca5e4e..19be8d7e6b 100644 --- a/db/migrate/20130816150110_add_statistics_to_public_body.rb +++ b/db/migrate/20130816150110_add_statistics_to_public_body.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddStatisticsToPublicBody < ActiveRecord::Migration[4.2] # 3.1 +class AddStatisticsToPublicBody < ActiveRecord::Migration[4.2] # 3.1 def self.up add_column :public_bodies, :info_requests_successful_count, :integer add_column :public_bodies, :info_requests_not_held_count, :integer diff --git a/db/migrate/20130822161803_add_prominence_fields_to_outgoing_message.rb b/db/migrate/20130822161803_add_prominence_fields_to_outgoing_message.rb index 1875172068..165e4e2bc5 100644 --- a/db/migrate/20130822161803_add_prominence_fields_to_outgoing_message.rb +++ b/db/migrate/20130822161803_add_prominence_fields_to_outgoing_message.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddProminenceFieldsToOutgoingMessage < ActiveRecord::Migration[4.2] # 3.1 +class AddProminenceFieldsToOutgoingMessage < ActiveRecord::Migration[4.2] # 3.1 def change add_column :outgoing_messages, :prominence, :string, :null => false, :default => 'normal' add_column :outgoing_messages, :prominence_reason, :text diff --git a/db/migrate/20130919151140_add_can_make_batch_requests_to_user.rb b/db/migrate/20130919151140_add_can_make_batch_requests_to_user.rb index 8e6c69f70c..8c414ad37d 100644 --- a/db/migrate/20130919151140_add_can_make_batch_requests_to_user.rb +++ b/db/migrate/20130919151140_add_can_make_batch_requests_to_user.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCanMakeBatchRequestsToUser < ActiveRecord::Migration[4.2] # 3.2 +class AddCanMakeBatchRequestsToUser < ActiveRecord::Migration[4.2] # 3.2 def change add_column :users, :can_make_batch_requests, :boolean, :default => false, :null => false end diff --git a/db/migrate/20131024114346_create_info_request_batches.rb b/db/migrate/20131024114346_create_info_request_batches.rb index b62327e80f..786ebc8d0f 100644 --- a/db/migrate/20131024114346_create_info_request_batches.rb +++ b/db/migrate/20131024114346_create_info_request_batches.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateInfoRequestBatches < ActiveRecord::Migration[4.2] # 3.2 +class CreateInfoRequestBatches < ActiveRecord::Migration[4.2] # 3.2 def up create_table :info_request_batches do |t| t.column :title, :text, :null => false diff --git a/db/migrate/20131024152540_add_body_to_info_request_batches.rb b/db/migrate/20131024152540_add_body_to_info_request_batches.rb index 917a77aa6a..2ceb231f22 100644 --- a/db/migrate/20131024152540_add_body_to_info_request_batches.rb +++ b/db/migrate/20131024152540_add_body_to_info_request_batches.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddBodyToInfoRequestBatches < ActiveRecord::Migration[4.2] # 3.2 +class AddBodyToInfoRequestBatches < ActiveRecord::Migration[4.2] # 3.2 def up add_column :info_request_batches, :body, :text add_index :info_request_batches, [:user_id, :body, :title] diff --git a/db/migrate/20131101155844_add_stats_denominator.rb b/db/migrate/20131101155844_add_stats_denominator.rb index 8891ce0479..faeba6f64a 100644 --- a/db/migrate/20131101155844_add_stats_denominator.rb +++ b/db/migrate/20131101155844_add_stats_denominator.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddStatsDenominator < ActiveRecord::Migration[4.2] # 3.2 +class AddStatsDenominator < ActiveRecord::Migration[4.2] # 3.2 def up add_column :public_bodies, :info_requests_visible_classified_count, :integer PublicBody.connection.execute("UPDATE public_bodies diff --git a/db/migrate/20131127105438_create_info_request_batch_public_bodies_join_table.rb b/db/migrate/20131127105438_create_info_request_batch_public_bodies_join_table.rb index 8c61121edd..557f4ef5bb 100644 --- a/db/migrate/20131127105438_create_info_request_batch_public_bodies_join_table.rb +++ b/db/migrate/20131127105438_create_info_request_batch_public_bodies_join_table.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateInfoRequestBatchPublicBodiesJoinTable < ActiveRecord::Migration[4.2] # 3.2 +class CreateInfoRequestBatchPublicBodiesJoinTable < ActiveRecord::Migration[4.2] # 3.2 def change create_table :info_request_batches_public_bodies, :id => false do |t| t.integer :info_request_batch_id diff --git a/db/migrate/20131127135622_add_sent_at_to_info_request_batch.rb b/db/migrate/20131127135622_add_sent_at_to_info_request_batch.rb index 5dd8a655f1..c313c1c501 100644 --- a/db/migrate/20131127135622_add_sent_at_to_info_request_batch.rb +++ b/db/migrate/20131127135622_add_sent_at_to_info_request_batch.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddSentAtToInfoRequestBatch < ActiveRecord::Migration[4.2] # 3.2 +class AddSentAtToInfoRequestBatch < ActiveRecord::Migration[4.2] # 3.2 def change add_column :info_request_batches, :sent_at, :datetime end diff --git a/db/migrate/20131211152641_create_public_body_change_requests.rb b/db/migrate/20131211152641_create_public_body_change_requests.rb index cfa211e532..17df838683 100644 --- a/db/migrate/20131211152641_create_public_body_change_requests.rb +++ b/db/migrate/20131211152641_create_public_body_change_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreatePublicBodyChangeRequests < ActiveRecord::Migration[4.2] # 3.2 +class CreatePublicBodyChangeRequests < ActiveRecord::Migration[4.2] # 3.2 def up create_table :public_body_change_requests do |t| t.column :user_email, :string diff --git a/db/migrate/20140325120619_create_spam_addresses.rb b/db/migrate/20140325120619_create_spam_addresses.rb index 97770af460..10c423fce6 100644 --- a/db/migrate/20140325120619_create_spam_addresses.rb +++ b/db/migrate/20140325120619_create_spam_addresses.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateSpamAddresses < ActiveRecord::Migration[4.2] # 3.2 +class CreateSpamAddresses < ActiveRecord::Migration[4.2] # 3.2 def change create_table :spam_addresses do |t| t.string :email, :null => false diff --git a/db/migrate/20140408145616_add_default_short_name_to_public_bodies.rb b/db/migrate/20140408145616_add_default_short_name_to_public_bodies.rb index 4e7bb6a35c..9c50277935 100644 --- a/db/migrate/20140408145616_add_default_short_name_to_public_bodies.rb +++ b/db/migrate/20140408145616_add_default_short_name_to_public_bodies.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDefaultShortNameToPublicBodies < ActiveRecord::Migration[4.2] # 3.2 +class AddDefaultShortNameToPublicBodies < ActiveRecord::Migration[4.2] # 3.2 def up change_column_default(:public_bodies, :short_name, '') diff --git a/db/migrate/20140528110536_update_track_things_index.rb b/db/migrate/20140528110536_update_track_things_index.rb index c907184247..f70a05d6c1 100644 --- a/db/migrate/20140528110536_update_track_things_index.rb +++ b/db/migrate/20140528110536_update_track_things_index.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class UpdateTrackThingsIndex < ActiveRecord::Migration[4.2] # 3.2 +class UpdateTrackThingsIndex < ActiveRecord::Migration[4.2] # 3.2 def up if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" diff --git a/db/migrate/20140710094405_create_public_body_headings_and_categories.rb b/db/migrate/20140710094405_create_public_body_headings_and_categories.rb index c890475546..d9fdfbd38d 100644 --- a/db/migrate/20140710094405_create_public_body_headings_and_categories.rb +++ b/db/migrate/20140710094405_create_public_body_headings_and_categories.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreatePublicBodyHeadingsAndCategories < ActiveRecord::Migration[4.2] # 3.2 +class CreatePublicBodyHeadingsAndCategories < ActiveRecord::Migration[4.2] # 3.2 def up create_table :public_body_headings, :force => true do |t| t.string :locale diff --git a/db/migrate/20140716131107_create_category_translation_tables.rb b/db/migrate/20140716131107_create_category_translation_tables.rb index 7a6fa89004..f471f4e777 100644 --- a/db/migrate/20140716131107_create_category_translation_tables.rb +++ b/db/migrate/20140716131107_create_category_translation_tables.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateCategoryTranslationTables < ActiveRecord::Migration[4.2] # 3.2 +class CreateCategoryTranslationTables < ActiveRecord::Migration[4.2] # 3.2 class PublicBodyCategory < ApplicationRecord translates :title, :description end diff --git a/db/migrate/20140801132719_add_index_to_info_request_events.rb b/db/migrate/20140801132719_add_index_to_info_request_events.rb index 7ff50c964d..8694748627 100644 --- a/db/migrate/20140801132719_add_index_to_info_request_events.rb +++ b/db/migrate/20140801132719_add_index_to_info_request_events.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddIndexToInfoRequestEvents < ActiveRecord::Migration[4.2] # 3.2 +class AddIndexToInfoRequestEvents < ActiveRecord::Migration[4.2] # 3.2 def change add_index :info_request_events, :event_type end diff --git a/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb b/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb index ccba889c1e..2240cff4cb 100644 --- a/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb +++ b/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDisplayOrderToCategoriesAndHeadings < ActiveRecord::Migration[4.2] # 3.2 +class AddDisplayOrderToCategoriesAndHeadings < ActiveRecord::Migration[4.2] # 3.2 def up add_column :public_body_categories_public_body_headings, :category_display_order, :integer rename_table :public_body_categories_public_body_headings, :public_body_category_links diff --git a/db/migrate/20140824191444_create_widget_votes.rb b/db/migrate/20140824191444_create_widget_votes.rb index 03c0577bbf..db1caa4150 100644 --- a/db/migrate/20140824191444_create_widget_votes.rb +++ b/db/migrate/20140824191444_create_widget_votes.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateWidgetVotes < ActiveRecord::Migration[4.2] # 3.2 +class CreateWidgetVotes < ActiveRecord::Migration[4.2] # 3.2 def change create_table :widget_votes do |t| t.string :cookie diff --git a/db/migrate/20151006101417_add_otp_enabled_to_users.rb b/db/migrate/20151006101417_add_otp_enabled_to_users.rb index 4f0858752c..7f502f43e6 100644 --- a/db/migrate/20151006101417_add_otp_enabled_to_users.rb +++ b/db/migrate/20151006101417_add_otp_enabled_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddOtpEnabledToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddOtpEnabledToUsers < ActiveRecord::Migration[4.2] # 3.2 def change add_column :users, :otp_enabled, :boolean, :default => false, :null => false end diff --git a/db/migrate/20151006104552_add_otp_secret_key_to_users.rb b/db/migrate/20151006104552_add_otp_secret_key_to_users.rb index 668152e085..7125c99789 100644 --- a/db/migrate/20151006104552_add_otp_secret_key_to_users.rb +++ b/db/migrate/20151006104552_add_otp_secret_key_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddOtpSecretKeyToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddOtpSecretKeyToUsers < ActiveRecord::Migration[4.2] # 3.2 def change add_column :users, :otp_secret_key, :string end diff --git a/db/migrate/20151006104739_add_counter_for_otp_to_users.rb b/db/migrate/20151006104739_add_counter_for_otp_to_users.rb index 4bf3468142..f3ad0c7128 100644 --- a/db/migrate/20151006104739_add_counter_for_otp_to_users.rb +++ b/db/migrate/20151006104739_add_counter_for_otp_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCounterForOtpToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddCounterForOtpToUsers < ActiveRecord::Migration[4.2] # 3.2 def change add_column :users, :otp_counter, :integer, :default => 1 end diff --git a/db/migrate/20151009162421_add_info_requests_visible_count_to_public_bodies.rb b/db/migrate/20151009162421_add_info_requests_visible_count_to_public_bodies.rb index 7ea56e638f..e3ad58fecf 100644 --- a/db/migrate/20151009162421_add_info_requests_visible_count_to_public_bodies.rb +++ b/db/migrate/20151009162421_add_info_requests_visible_count_to_public_bodies.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestsVisibleCountToPublicBodies < ActiveRecord::Migration[4.2] # 3.2 +class AddInfoRequestsVisibleCountToPublicBodies < ActiveRecord::Migration[4.2] # 3.2 def up add_column :public_bodies, :info_requests_visible_count, :integer, :null => false, :default => 0 diff --git a/db/migrate/20151020112248_set_longer_length_for_track_things_track_query.rb b/db/migrate/20151020112248_set_longer_length_for_track_things_track_query.rb index e0cdc43d58..19b9090981 100644 --- a/db/migrate/20151020112248_set_longer_length_for_track_things_track_query.rb +++ b/db/migrate/20151020112248_set_longer_length_for_track_things_track_query.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class SetLongerLengthForTrackThingsTrackQuery < ActiveRecord::Migration[4.2] # 3.2 +class SetLongerLengthForTrackThingsTrackQuery < ActiveRecord::Migration[4.2] # 3.2 def up change_column :track_things, :track_query, :string, :limit => 500 end diff --git a/db/migrate/20151104131702_add_last_public_response_at_to_info_request.rb b/db/migrate/20151104131702_add_last_public_response_at_to_info_request.rb index d33fdd0394..2b4ee2cbcc 100644 --- a/db/migrate/20151104131702_add_last_public_response_at_to_info_request.rb +++ b/db/migrate/20151104131702_add_last_public_response_at_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddLastPublicResponseAtToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddLastPublicResponseAtToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def up add_column :info_requests, :last_public_response_at, :datetime, :null => true diff --git a/db/migrate/20160526154304_add_confirmed_not_spam_to_users.rb b/db/migrate/20160526154304_add_confirmed_not_spam_to_users.rb index 8c7f89fd27..e34661c19b 100644 --- a/db/migrate/20160526154304_add_confirmed_not_spam_to_users.rb +++ b/db/migrate/20160526154304_add_confirmed_not_spam_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddConfirmedNotSpamToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddConfirmedNotSpamToUsers < ActiveRecord::Migration[4.2] # 3.2 def change add_column :users, :confirmed_not_spam, :boolean, :default => false, :null => false end diff --git a/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb b/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb index ed7bff9cc7..ca8621f2ab 100644 --- a/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb +++ b/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddRejectIncomingAtMtaToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddRejectIncomingAtMtaToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def up add_column :info_requests, :reject_incoming_at_mta, :boolean, :default => false, :null => false end diff --git a/db/migrate/20160602145046_add_rejected_incoming_count_to_info_request.rb b/db/migrate/20160602145046_add_rejected_incoming_count_to_info_request.rb index c13dc585d6..5914a2b243 100644 --- a/db/migrate/20160602145046_add_rejected_incoming_count_to_info_request.rb +++ b/db/migrate/20160602145046_add_rejected_incoming_count_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddRejectedIncomingCountToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddRejectedIncomingCountToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def up add_column :info_requests, :rejected_incoming_count, :integer, :default => 0 end diff --git a/db/migrate/20160613145644_add_comments_count_to_users.rb b/db/migrate/20160613145644_add_comments_count_to_users.rb index 50778ee536..56cf8f2146 100644 --- a/db/migrate/20160613145644_add_comments_count_to_users.rb +++ b/db/migrate/20160613145644_add_comments_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddCommentsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddCommentsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :comments_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160613151127_add_info_requests_count_to_users.rb b/db/migrate/20160613151127_add_info_requests_count_to_users.rb index 32fd24578f..5998086180 100644 --- a/db/migrate/20160613151127_add_info_requests_count_to_users.rb +++ b/db/migrate/20160613151127_add_info_requests_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddInfoRequestsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :info_requests_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160613151912_add_track_things_count_to_users.rb b/db/migrate/20160613151912_add_track_things_count_to_users.rb index 2823d59e4a..0cd71791ec 100644 --- a/db/migrate/20160613151912_add_track_things_count_to_users.rb +++ b/db/migrate/20160613151912_add_track_things_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTrackThingsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddTrackThingsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :track_things_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160613152433_add_request_classifications_count_to_users.rb b/db/migrate/20160613152433_add_request_classifications_count_to_users.rb index b4607797b5..00490a59b3 100644 --- a/db/migrate/20160613152433_add_request_classifications_count_to_users.rb +++ b/db/migrate/20160613152433_add_request_classifications_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddRequestClassificationsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddRequestClassificationsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :request_classifications_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160613153739_add_public_body_change_requests_count_to_users.rb b/db/migrate/20160613153739_add_public_body_change_requests_count_to_users.rb index c1ae7eb21a..a87000fa3d 100644 --- a/db/migrate/20160613153739_add_public_body_change_requests_count_to_users.rb +++ b/db/migrate/20160613153739_add_public_body_change_requests_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddPublicBodyChangeRequestsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddPublicBodyChangeRequestsCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :public_body_change_requests_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160613154616_add_info_request_batches_count_to_users.rb b/db/migrate/20160613154616_add_info_request_batches_count_to_users.rb index 27658a509d..9b27c98688 100644 --- a/db/migrate/20160613154616_add_info_request_batches_count_to_users.rb +++ b/db/migrate/20160613154616_add_info_request_batches_count_to_users.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddInfoRequestBatchesCountToUsers < ActiveRecord::Migration[4.2] # 3.2 +class AddInfoRequestBatchesCountToUsers < ActiveRecord::Migration[4.2] # 3.2 def up add_column :users, :info_request_batches_count, :integer, :default => 0, :null => false diff --git a/db/migrate/20160701155339_remove_comment_type_from_comment.rb b/db/migrate/20160701155339_remove_comment_type_from_comment.rb index 2fa51c587d..64c42b1e00 100644 --- a/db/migrate/20160701155339_remove_comment_type_from_comment.rb +++ b/db/migrate/20160701155339_remove_comment_type_from_comment.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveCommentTypeFromComment < ActiveRecord::Migration[4.2] # 3.2 +class RemoveCommentTypeFromComment < ActiveRecord::Migration[4.2] # 3.2 def up remove_column :comments, :comment_type end diff --git a/db/migrate/20160907144809_add_delivery_status_to_mail_server_logs.rb b/db/migrate/20160907144809_add_delivery_status_to_mail_server_logs.rb index dc5cb4b706..7209bba0d4 100644 --- a/db/migrate/20160907144809_add_delivery_status_to_mail_server_logs.rb +++ b/db/migrate/20160907144809_add_delivery_status_to_mail_server_logs.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDeliveryStatusToMailServerLogs < ActiveRecord::Migration[4.2] # 3.2 +class AddDeliveryStatusToMailServerLogs < ActiveRecord::Migration[4.2] # 3.2 def up add_column :mail_server_logs, :delivery_status, :string end diff --git a/db/migrate/20161006142352_create_flipper_tables.rb b/db/migrate/20161006142352_create_flipper_tables.rb index 0e52db3105..7b9c8122f1 100644 --- a/db/migrate/20161006142352_create_flipper_tables.rb +++ b/db/migrate/20161006142352_create_flipper_tables.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateFlipperTables < ActiveRecord::Migration[4.2] # 3.2 +class CreateFlipperTables < ActiveRecord::Migration[4.2] # 3.2 def self.up create_table :flipper_features do |t| t.string :key, null: false diff --git a/db/migrate/20161101110656_create_pro_accounts.rb b/db/migrate/20161101110656_create_pro_accounts.rb index a9a358c964..29c7075fb9 100644 --- a/db/migrate/20161101110656_create_pro_accounts.rb +++ b/db/migrate/20161101110656_create_pro_accounts.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateProAccounts < ActiveRecord::Migration[4.2] # 3.2 +class CreateProAccounts < ActiveRecord::Migration[4.2] # 3.2 def change create_table :pro_accounts do |t| t.column :user_id, :integer, null: false diff --git a/db/migrate/20161101151318_create_embargoes.rb b/db/migrate/20161101151318_create_embargoes.rb index ba75c51c9f..da90669bd6 100644 --- a/db/migrate/20161101151318_create_embargoes.rb +++ b/db/migrate/20161101151318_create_embargoes.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateEmbargoes < ActiveRecord::Migration[4.2] # 3.2 +class CreateEmbargoes < ActiveRecord::Migration[4.2] # 3.2 def change create_table :embargoes do |t| t.belongs_to :info_request, index: true diff --git a/db/migrate/20161116121007_create_draft_info_requests.rb b/db/migrate/20161116121007_create_draft_info_requests.rb index a84af409d0..5ad5d92aba 100644 --- a/db/migrate/20161116121007_create_draft_info_requests.rb +++ b/db/migrate/20161116121007_create_draft_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateDraftInfoRequests < ActiveRecord::Migration[4.2] # 3.2 +class CreateDraftInfoRequests < ActiveRecord::Migration[4.2] # 3.2 def change create_table :draft_info_requests do |t| t.string :title diff --git a/db/migrate/20161128095350_add_duration_to_embargo.rb b/db/migrate/20161128095350_add_duration_to_embargo.rb index 8efa96ba3d..0d26aad27c 100644 --- a/db/migrate/20161128095350_add_duration_to_embargo.rb +++ b/db/migrate/20161128095350_add_duration_to_embargo.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDurationToEmbargo < ActiveRecord::Migration[4.2] # 3.2 +class AddDurationToEmbargo < ActiveRecord::Migration[4.2] # 3.2 def change add_column :embargoes, :embargo_duration, :string end diff --git a/db/migrate/20161206174634_add_date_initial_request_last_sent_at_to_info_request.rb b/db/migrate/20161206174634_add_date_initial_request_last_sent_at_to_info_request.rb index bc2eb355d7..ea8d7f08dc 100644 --- a/db/migrate/20161206174634_add_date_initial_request_last_sent_at_to_info_request.rb +++ b/db/migrate/20161206174634_add_date_initial_request_last_sent_at_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDateInitialRequestLastSentAtToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddDateInitialRequestLastSentAtToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def change add_column :info_requests, :date_initial_request_last_sent_at, :date end diff --git a/db/migrate/20161206175711_add_date_response_required_by_to_info_request.rb b/db/migrate/20161206175711_add_date_response_required_by_to_info_request.rb index a2ad8604ba..9c78d32e0a 100644 --- a/db/migrate/20161206175711_add_date_response_required_by_to_info_request.rb +++ b/db/migrate/20161206175711_add_date_response_required_by_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDateResponseRequiredByToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddDateResponseRequiredByToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def change add_column :info_requests, :date_response_required_by, :date end diff --git a/db/migrate/20161206175737_add_date_very_overdue_after_to_info_request.rb b/db/migrate/20161206175737_add_date_very_overdue_after_to_info_request.rb index a548b4bdd5..bdf5f86aa0 100644 --- a/db/migrate/20161206175737_add_date_very_overdue_after_to_info_request.rb +++ b/db/migrate/20161206175737_add_date_very_overdue_after_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDateVeryOverdueAfterToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 +class AddDateVeryOverdueAfterToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 def change add_column :info_requests, :date_very_overdue_after, :date end diff --git a/db/migrate/20161207184708_create_embargo_extensions.rb b/db/migrate/20161207184708_create_embargo_extensions.rb index 165c02fce3..5af96ee364 100644 --- a/db/migrate/20161207184708_create_embargo_extensions.rb +++ b/db/migrate/20161207184708_create_embargo_extensions.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateEmbargoExtensions < ActiveRecord::Migration[4.2] # 3.2 +class CreateEmbargoExtensions < ActiveRecord::Migration[4.2] # 3.2 def change create_table :embargo_extensions do |t| t.integer :embargo_id diff --git a/db/migrate/20161222101600_add_last_event_forming_initial_request_id_to_info_requests.rb b/db/migrate/20161222101600_add_last_event_forming_initial_request_id_to_info_requests.rb index 6d85b28c57..d47cd19a95 100644 --- a/db/migrate/20161222101600_add_last_event_forming_initial_request_id_to_info_requests.rb +++ b/db/migrate/20161222101600_add_last_event_forming_initial_request_id_to_info_requests.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddLastEventFormingInitialRequestIdToInfoRequests < ActiveRecord::Migration[4.2] # 3.2 +class AddLastEventFormingInitialRequestIdToInfoRequests < ActiveRecord::Migration[4.2] # 3.2 def change add_column :info_requests, :last_event_forming_initial_request_id, :integer end diff --git a/db/migrate/20170216101547_add_attention_requested_to_comment.rb b/db/migrate/20170216101547_add_attention_requested_to_comment.rb index 80dfc68042..8ac9ee3fa2 100644 --- a/db/migrate/20170216101547_add_attention_requested_to_comment.rb +++ b/db/migrate/20170216101547_add_attention_requested_to_comment.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddAttentionRequestedToComment < ActiveRecord::Migration[4.2] # 4.0 +class AddAttentionRequestedToComment < ActiveRecord::Migration[4.2] # 4.0 def change add_column :comments, :attention_requested, :boolean, :null => false, :default => false diff --git a/db/migrate/20170227140831_rolify_create_roles.rb b/db/migrate/20170227140831_rolify_create_roles.rb index 4adb0b84d2..f7e3156485 100644 --- a/db/migrate/20170227140831_rolify_create_roles.rb +++ b/db/migrate/20170227140831_rolify_create_roles.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RolifyCreateRoles < ActiveRecord::Migration[4.2] # 4.0 +class RolifyCreateRoles < ActiveRecord::Migration[4.2] # 4.0 def change create_table(:roles) do |t| t.string :name diff --git a/db/migrate/20170301163735_create_draft_info_request_batches.rb b/db/migrate/20170301163735_create_draft_info_request_batches.rb index 94a675967d..8b5e2a329e 100644 --- a/db/migrate/20170301163735_create_draft_info_request_batches.rb +++ b/db/migrate/20170301163735_create_draft_info_request_batches.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateDraftInfoRequestBatches < ActiveRecord::Migration[4.2] # 4.0 +class CreateDraftInfoRequestBatches < ActiveRecord::Migration[4.2] # 4.0 def change create_table :draft_info_request_batches do |t| t.string :title diff --git a/db/migrate/20170301164705_create_draft_info_request_batches_public_bodies_table.rb b/db/migrate/20170301164705_create_draft_info_request_batches_public_bodies_table.rb index 2823c7d943..ddc9ed8144 100644 --- a/db/migrate/20170301164705_create_draft_info_request_batches_public_bodies_table.rb +++ b/db/migrate/20170301164705_create_draft_info_request_batches_public_bodies_table.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateDraftInfoRequestBatchesPublicBodiesTable < ActiveRecord::Migration[4.2] # 4.0 +class CreateDraftInfoRequestBatchesPublicBodiesTable < ActiveRecord::Migration[4.2] # 4.0 def change create_table :draft_info_request_batches_public_bodies, :id => false do |t| diff --git a/db/migrate/20170316170248_edit_info_request_batch_index.rb b/db/migrate/20170316170248_edit_info_request_batch_index.rb index a29017526f..60e9231dd1 100644 --- a/db/migrate/20170316170248_edit_info_request_batch_index.rb +++ b/db/migrate/20170316170248_edit_info_request_batch_index.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- -class EditInfoRequestBatchIndex < ActiveRecord::Migration[4.2] # 4.0 +class EditInfoRequestBatchIndex < ActiveRecord::Migration[4.2] # 4.0 def change - remove_index :info_request_batches, :column => [:user_id, :body, :title] + remove_index :info_request_batches, :column => [:user_id, :body, :title] add_index :info_request_batches, [:user_id, :title] end end diff --git a/db/migrate/20170323165519_add_embargo_duration_to_draft_info_request_batch.rb b/db/migrate/20170323165519_add_embargo_duration_to_draft_info_request_batch.rb index a0c6741d1f..83cda383d7 100644 --- a/db/migrate/20170323165519_add_embargo_duration_to_draft_info_request_batch.rb +++ b/db/migrate/20170323165519_add_embargo_duration_to_draft_info_request_batch.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEmbargoDurationToDraftInfoRequestBatch < ActiveRecord::Migration[4.2] # 4.0 +class AddEmbargoDurationToDraftInfoRequestBatch < ActiveRecord::Migration[4.2] # 4.0 def change add_column :draft_info_request_batches, :embargo_duration, :string end diff --git a/db/migrate/20170328100359_add_embargo_duration_to_info_request_batch.rb b/db/migrate/20170328100359_add_embargo_duration_to_info_request_batch.rb index ce6f18e17b..4dba5c1974 100644 --- a/db/migrate/20170328100359_add_embargo_duration_to_info_request_batch.rb +++ b/db/migrate/20170328100359_add_embargo_duration_to_info_request_batch.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddEmbargoDurationToInfoRequestBatch < ActiveRecord::Migration[4.2] # 4.0 +class AddEmbargoDurationToInfoRequestBatch < ActiveRecord::Migration[4.2] # 4.0 def change add_column :info_request_batches, :embargo_duration, :string end diff --git a/db/migrate/20170411113908_create_alaveteli_pro_request_summaries.rb b/db/migrate/20170411113908_create_alaveteli_pro_request_summaries.rb index 6188f7c01b..0fc75bfa7b 100644 --- a/db/migrate/20170411113908_create_alaveteli_pro_request_summaries.rb +++ b/db/migrate/20170411113908_create_alaveteli_pro_request_summaries.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateAlaveteliProRequestSummaries < ActiveRecord::Migration[4.2] # 4.1 +class CreateAlaveteliProRequestSummaries < ActiveRecord::Migration[4.2] # 4.1 def change create_table :request_summaries do |t| t.text :title diff --git a/db/migrate/20170412141214_add_unique_index_to_summarisable.rb b/db/migrate/20170412141214_add_unique_index_to_summarisable.rb index f5b978423b..2bd4a59a6d 100644 --- a/db/migrate/20170412141214_add_unique_index_to_summarisable.rb +++ b/db/migrate/20170412141214_add_unique_index_to_summarisable.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUniqueIndexToSummarisable < ActiveRecord::Migration[4.2] # 4.1 +class AddUniqueIndexToSummarisable < ActiveRecord::Migration[4.2] # 4.1 def change add_index :request_summaries, [:summarisable_type, :summarisable_id], diff --git a/db/migrate/20170412143304_make_summarisable_not_null.rb b/db/migrate/20170412143304_make_summarisable_not_null.rb index 7a8e3d9474..c071581bb6 100644 --- a/db/migrate/20170412143304_make_summarisable_not_null.rb +++ b/db/migrate/20170412143304_make_summarisable_not_null.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class MakeSummarisableNotNull < ActiveRecord::Migration[4.2] # 4.1 +class MakeSummarisableNotNull < ActiveRecord::Migration[4.2] # 4.1 def change change_column_null :request_summaries, :summarisable_type, false change_column_null :request_summaries, :summarisable_id, false diff --git a/db/migrate/20170412145313_add_user_to_request_summary.rb b/db/migrate/20170412145313_add_user_to_request_summary.rb index af643f01b4..a43a469818 100644 --- a/db/migrate/20170412145313_add_user_to_request_summary.rb +++ b/db/migrate/20170412145313_add_user_to_request_summary.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUserToRequestSummary < ActiveRecord::Migration[4.2] # 4.1 +class AddUserToRequestSummary < ActiveRecord::Migration[4.2] # 4.1 def change add_reference :request_summaries, :user, index: true, null: false end diff --git a/db/migrate/20170412150729_create_alaveteli_pro_request_summary_categories.rb b/db/migrate/20170412150729_create_alaveteli_pro_request_summary_categories.rb index c56798612f..84edb4e9e2 100644 --- a/db/migrate/20170412150729_create_alaveteli_pro_request_summary_categories.rb +++ b/db/migrate/20170412150729_create_alaveteli_pro_request_summary_categories.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateAlaveteliProRequestSummaryCategories < ActiveRecord::Migration[4.2] # 4.1 +class CreateAlaveteliProRequestSummaryCategories < ActiveRecord::Migration[4.2] # 4.1 def change create_table :request_summary_categories do |t| t.text :slug, :unique => true diff --git a/db/migrate/20170413135231_allow_user_to_be_null_on_request_summary.rb b/db/migrate/20170413135231_allow_user_to_be_null_on_request_summary.rb index 1ca7944929..4957c10772 100644 --- a/db/migrate/20170413135231_allow_user_to_be_null_on_request_summary.rb +++ b/db/migrate/20170413135231_allow_user_to_be_null_on_request_summary.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AllowUserToBeNullOnRequestSummary < ActiveRecord::Migration[4.2] # 4.1 +class AllowUserToBeNullOnRequestSummary < ActiveRecord::Migration[4.2] # 4.1 def change change_column_null :request_summaries, :user_id, true end diff --git a/db/migrate/20170414140927_create_incoming_message_error.rb b/db/migrate/20170414140927_create_incoming_message_error.rb index 27c9babddc..e9f5b4919c 100644 --- a/db/migrate/20170414140927_create_incoming_message_error.rb +++ b/db/migrate/20170414140927_create_incoming_message_error.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateIncomingMessageError < ActiveRecord::Migration[4.2] # 4.1 +class CreateIncomingMessageError < ActiveRecord::Migration[4.2] # 4.1 def change create_table :incoming_message_errors do |t| t.timestamps null: false diff --git a/db/migrate/20170421145745_add_request_created_at_and_request_updated_at_to_request_summary.rb b/db/migrate/20170421145745_add_request_created_at_and_request_updated_at_to_request_summary.rb index f03c2ecf6d..10c9e330c9 100644 --- a/db/migrate/20170421145745_add_request_created_at_and_request_updated_at_to_request_summary.rb +++ b/db/migrate/20170421145745_add_request_created_at_and_request_updated_at_to_request_summary.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddRequestCreatedAtAndRequestUpdatedAtToRequestSummary < ActiveRecord::Migration[4.2] # 4.1 +class AddRequestCreatedAtAndRequestUpdatedAtToRequestSummary < ActiveRecord::Migration[4.2] # 4.1 def change add_column :request_summaries, :request_created_at, :datetime, null: false, default: Time.now add_column :request_summaries, :request_updated_at, :datetime, null: false, default: Time.now diff --git a/db/migrate/20170509210708_add_use_notifications_to_info_request.rb b/db/migrate/20170509210708_add_use_notifications_to_info_request.rb index bb53a6371c..449b02d88b 100644 --- a/db/migrate/20170509210708_add_use_notifications_to_info_request.rb +++ b/db/migrate/20170509210708_add_use_notifications_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUseNotificationsToInfoRequest < ActiveRecord::Migration[4.2] # 4.1 +class AddUseNotificationsToInfoRequest < ActiveRecord::Migration[4.2] # 4.1 def change add_column :info_requests, :use_notifications, :boolean end diff --git a/db/migrate/20170516120853_create_notifications.rb b/db/migrate/20170516120853_create_notifications.rb index df408274fa..4d26bfae27 100644 --- a/db/migrate/20170516120853_create_notifications.rb +++ b/db/migrate/20170516120853_create_notifications.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateNotifications < ActiveRecord::Migration[4.2] # 4.1 +class CreateNotifications < ActiveRecord::Migration[4.2] # 4.1 def change create_table :notifications do |t| t.references :info_request_event, null: false, index: true diff --git a/db/migrate/20170516132204_add_daily_summary_time_to_user.rb b/db/migrate/20170516132204_add_daily_summary_time_to_user.rb index 1d4badeab9..3ff54cc0a5 100644 --- a/db/migrate/20170516132204_add_daily_summary_time_to_user.rb +++ b/db/migrate/20170516132204_add_daily_summary_time_to_user.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddDailySummaryTimeToUser < ActiveRecord::Migration[4.2] # 4.1 +class AddDailySummaryTimeToUser < ActiveRecord::Migration[4.2] # 4.1 def change add_column :users, :daily_summary_hour, :integer add_column :users, :daily_summary_minute, :integer diff --git a/db/migrate/20170606141753_add_last_event_time_to_info_request.rb b/db/migrate/20170606141753_add_last_event_time_to_info_request.rb index 8f3fc96502..4059db66bd 100644 --- a/db/migrate/20170606141753_add_last_event_time_to_info_request.rb +++ b/db/migrate/20170606141753_add_last_event_time_to_info_request.rb @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -class AddLastEventTimeToInfoRequest < ActiveRecord::Migration[4.2] # 4.1 +class AddLastEventTimeToInfoRequest < ActiveRecord::Migration[4.2] # 4.1 def change add_column :info_requests, :last_event_time, :datetime end diff --git a/db/migrate/20170621112453_remove_default_value_from_request_created_at_and_request_updated_at_on_request_summary.rb b/db/migrate/20170621112453_remove_default_value_from_request_created_at_and_request_updated_at_on_request_summary.rb index b80e718064..7a5ae68c00 100644 --- a/db/migrate/20170621112453_remove_default_value_from_request_created_at_and_request_updated_at_on_request_summary.rb +++ b/db/migrate/20170621112453_remove_default_value_from_request_created_at_and_request_updated_at_on_request_summary.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveDefaultValueFromRequestCreatedAtAndRequestUpdatedAtOnRequestSummary < ActiveRecord::Migration[4.2] # 4.1 +class RemoveDefaultValueFromRequestCreatedAtAndRequestUpdatedAtOnRequestSummary < ActiveRecord::Migration[4.2] # 4.1 def up change_column_default :request_summaries, :request_created_at, nil change_column_default :request_summaries, :request_updated_at, nil diff --git a/db/migrate/20170704143210_drop_unconventional_public_body_constraints.rb b/db/migrate/20170704143210_drop_unconventional_public_body_constraints.rb index 4b561d8c07..699f0c5e0c 100644 --- a/db/migrate/20170704143210_drop_unconventional_public_body_constraints.rb +++ b/db/migrate/20170704143210_drop_unconventional_public_body_constraints.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class DropUnconventionalPublicBodyConstraints < ActiveRecord::Migration[4.2] # 4.1 +class DropUnconventionalPublicBodyConstraints < ActiveRecord::Migration[4.2] # 4.1 DATA = { PublicBody => [:short_name, :home_page, :notes, diff --git a/db/migrate/20170717141302_drop_public_body_translated_columns.rb b/db/migrate/20170717141302_drop_public_body_translated_columns.rb index 9f162870f5..8385e1e010 100644 --- a/db/migrate/20170717141302_drop_public_body_translated_columns.rb +++ b/db/migrate/20170717141302_drop_public_body_translated_columns.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class DropPublicBodyTranslatedColumns < ActiveRecord::Migration[4.2] # 4.1 +class DropPublicBodyTranslatedColumns < ActiveRecord::Migration[4.2] # 4.1 def up PublicBody.transaction do PublicBody.find_each do |record| diff --git a/db/migrate/20170718261524_add_expiring_notification_at.rb b/db/migrate/20170718261524_add_expiring_notification_at.rb index 8843c03d7f..9eee2b5995 100644 --- a/db/migrate/20170718261524_add_expiring_notification_at.rb +++ b/db/migrate/20170718261524_add_expiring_notification_at.rb @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -class AddExpiringNotificationAt < ActiveRecord::Migration[4.2] # 4.1 +class AddExpiringNotificationAt < ActiveRecord::Migration[4.2] # 4.1 def up unless column_exists?(:embargoes, :expiring_notification_at) add_column :embargoes, :expiring_notification_at, :datetime diff --git a/db/migrate/20170726114401_add_expired_to_notification.rb b/db/migrate/20170726114401_add_expired_to_notification.rb index 3f6b04a012..242490470e 100644 --- a/db/migrate/20170726114401_add_expired_to_notification.rb +++ b/db/migrate/20170726114401_add_expired_to_notification.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddExpiredToNotification < ActiveRecord::Migration[4.2] # 4.1 +class AddExpiredToNotification < ActiveRecord::Migration[4.2] # 4.1 def change add_column :notifications, :expired, :boolean, default: false end diff --git a/db/migrate/20170825150448_add_stripe_customer_id_to_pro_account.rb b/db/migrate/20170825150448_add_stripe_customer_id_to_pro_account.rb index e808a0dd04..d9af07bc57 100644 --- a/db/migrate/20170825150448_add_stripe_customer_id_to_pro_account.rb +++ b/db/migrate/20170825150448_add_stripe_customer_id_to_pro_account.rb @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -class AddStripeCustomerIdToProAccount < ActiveRecord::Migration[4.2] +class AddStripeCustomerIdToProAccount < ActiveRecord::Migration[4.2] def up unless column_exists?(:pro_accounts, :stripe_customer_id) add_column :pro_accounts, :stripe_customer_id, :string diff --git a/db/migrate/20170914164031_remove_purge_request.rb b/db/migrate/20170914164031_remove_purge_request.rb index dd12876f98..76ae9f2906 100644 --- a/db/migrate/20170914164031_remove_purge_request.rb +++ b/db/migrate/20170914164031_remove_purge_request.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemovePurgeRequest < ActiveRecord::Migration[4.2] +class RemovePurgeRequest < ActiveRecord::Migration[4.2] def up drop_table :purge_requests end diff --git a/db/migrate/20170922160120_remove_admin_level.rb b/db/migrate/20170922160120_remove_admin_level.rb index 0c84366a14..c9737ba5fa 100644 --- a/db/migrate/20170922160120_remove_admin_level.rb +++ b/db/migrate/20170922160120_remove_admin_level.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class RemoveAdminLevel < ActiveRecord::Migration[4.2] +class RemoveAdminLevel < ActiveRecord::Migration[4.2] def self.up remove_column :users, :admin_level end diff --git a/db/migrate/20171207140915_create_announcements.rb b/db/migrate/20171207140915_create_announcements.rb index 5bbef4bd5e..e1da3e99fe 100644 --- a/db/migrate/20171207140915_create_announcements.rb +++ b/db/migrate/20171207140915_create_announcements.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateAnnouncements < ActiveRecord::Migration[4.2] +class CreateAnnouncements < ActiveRecord::Migration[4.2] def change create_table :announcements do |t| t.string :visibility diff --git a/db/migrate/20171207140945_create_announcement_dismissals.rb b/db/migrate/20171207140945_create_announcement_dismissals.rb index 1bcf015f7f..07213bf4ae 100644 --- a/db/migrate/20171207140945_create_announcement_dismissals.rb +++ b/db/migrate/20171207140945_create_announcement_dismissals.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class CreateAnnouncementDismissals < ActiveRecord::Migration[4.2] +class CreateAnnouncementDismissals < ActiveRecord::Migration[4.2] def change create_table :announcement_dismissals, force: true do |t| t.references :announcement, index: true, foreign_key: true, null: false diff --git a/db/migrate/20171222121709_change_user_salt_null.rb b/db/migrate/20171222121709_change_user_salt_null.rb index 7841f4a0b9..73a2e94341 100644 --- a/db/migrate/20171222121709_change_user_salt_null.rb +++ b/db/migrate/20171222121709_change_user_salt_null.rb @@ -1,4 +1,4 @@ -class ChangeUserSaltNull < ActiveRecord::Migration[4.2] +class ChangeUserSaltNull < ActiveRecord::Migration[4.2] def change change_column_null :users, :salt, true end diff --git a/db/migrate/20180412135329_fix_broken_migration_timestamps.rb b/db/migrate/20180412135329_fix_broken_migration_timestamps.rb index ec4687c0a7..cef4f1dfbd 100644 --- a/db/migrate/20180412135329_fix_broken_migration_timestamps.rb +++ b/db/migrate/20180412135329_fix_broken_migration_timestamps.rb @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -class FixBrokenMigrationTimestamps < ActiveRecord::Migration[4.2] +class FixBrokenMigrationTimestamps < ActiveRecord::Migration[4.2] def up # We can just delete the old migration version from the database beacuse: # * We know the renamed migration has been applied, because the timestamp diff --git a/db/migrate/20180418154555_add_timestamps_to_foi_attachments.rb b/db/migrate/20180418154555_add_timestamps_to_foi_attachments.rb index fbf17fb171..c18aa00ea9 100644 --- a/db/migrate/20180418154555_add_timestamps_to_foi_attachments.rb +++ b/db/migrate/20180418154555_add_timestamps_to_foi_attachments.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToFoiAttachments < ActiveRecord::Migration[4.2] +class AddTimestampsToFoiAttachments < ActiveRecord::Migration[4.2] def change add_timestamps(:foi_attachments, null: true) end diff --git a/db/migrate/20180418154949_add_timestamps_to_holidays.rb b/db/migrate/20180418154949_add_timestamps_to_holidays.rb index b0a5217797..2004ed5ac4 100644 --- a/db/migrate/20180418154949_add_timestamps_to_holidays.rb +++ b/db/migrate/20180418154949_add_timestamps_to_holidays.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToHolidays < ActiveRecord::Migration[4.2] +class AddTimestampsToHolidays < ActiveRecord::Migration[4.2] def change add_timestamps(:holidays, null: true) end diff --git a/db/migrate/20180418155130_add_updated_at_to_info_request_events.rb b/db/migrate/20180418155130_add_updated_at_to_info_request_events.rb index 2357023062..d55fecb7d2 100644 --- a/db/migrate/20180418155130_add_updated_at_to_info_request_events.rb +++ b/db/migrate/20180418155130_add_updated_at_to_info_request_events.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUpdatedAtToInfoRequestEvents < ActiveRecord::Migration[4.2] +class AddUpdatedAtToInfoRequestEvents < ActiveRecord::Migration[4.2] def up add_column :info_request_events, :updated_at, :datetime end diff --git a/db/migrate/20180418155632_add_timestamps_to_profile_photos.rb b/db/migrate/20180418155632_add_timestamps_to_profile_photos.rb index b450f61ea5..ae9d4a7016 100644 --- a/db/migrate/20180418155632_add_timestamps_to_profile_photos.rb +++ b/db/migrate/20180418155632_add_timestamps_to_profile_photos.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToProfilePhotos < ActiveRecord::Migration[4.2] +class AddTimestampsToProfilePhotos < ActiveRecord::Migration[4.2] def change add_timestamps(:profile_photos, null: true) end diff --git a/db/migrate/20180418155850_add_timestamps_to_public_body_category_links.rb b/db/migrate/20180418155850_add_timestamps_to_public_body_category_links.rb index bb8997768b..5c93cf444b 100644 --- a/db/migrate/20180418155850_add_timestamps_to_public_body_category_links.rb +++ b/db/migrate/20180418155850_add_timestamps_to_public_body_category_links.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToPublicBodyCategoryLinks < ActiveRecord::Migration[4.2] +class AddTimestampsToPublicBodyCategoryLinks < ActiveRecord::Migration[4.2] def change add_timestamps(:public_body_category_links, null: true) end diff --git a/db/migrate/20180418155927_add_timestamps_to_public_body_categories.rb b/db/migrate/20180418155927_add_timestamps_to_public_body_categories.rb index 1248480429..34d3d6ef12 100644 --- a/db/migrate/20180418155927_add_timestamps_to_public_body_categories.rb +++ b/db/migrate/20180418155927_add_timestamps_to_public_body_categories.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToPublicBodyCategories < ActiveRecord::Migration[4.2] +class AddTimestampsToPublicBodyCategories < ActiveRecord::Migration[4.2] def change add_timestamps(:public_body_categories, null: true) end diff --git a/db/migrate/20180418160008_add_timestamps_to_public_body_headings.rb b/db/migrate/20180418160008_add_timestamps_to_public_body_headings.rb index 76efaab1ab..9ac8b5175a 100644 --- a/db/migrate/20180418160008_add_timestamps_to_public_body_headings.rb +++ b/db/migrate/20180418160008_add_timestamps_to_public_body_headings.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToPublicBodyHeadings < ActiveRecord::Migration[4.2] +class AddTimestampsToPublicBodyHeadings < ActiveRecord::Migration[4.2] def change add_timestamps(:public_body_headings, null: true) end diff --git a/db/migrate/20180418160048_add_timestamps_to_raw_emails.rb b/db/migrate/20180418160048_add_timestamps_to_raw_emails.rb index f3fdeac1f7..1498b1226e 100644 --- a/db/migrate/20180418160048_add_timestamps_to_raw_emails.rb +++ b/db/migrate/20180418160048_add_timestamps_to_raw_emails.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToRawEmails < ActiveRecord::Migration[4.2] +class AddTimestampsToRawEmails < ActiveRecord::Migration[4.2] def change add_timestamps(:raw_emails, null: true) end diff --git a/db/migrate/20180418160204_add_timestamps_to_user_info_request_sent_alerts.rb b/db/migrate/20180418160204_add_timestamps_to_user_info_request_sent_alerts.rb index fbc46308eb..fd453d48a9 100644 --- a/db/migrate/20180418160204_add_timestamps_to_user_info_request_sent_alerts.rb +++ b/db/migrate/20180418160204_add_timestamps_to_user_info_request_sent_alerts.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToUserInfoRequestSentAlerts < ActiveRecord::Migration[4.2] +class AddTimestampsToUserInfoRequestSentAlerts < ActiveRecord::Migration[4.2] def change add_timestamps(:user_info_request_sent_alerts, null: true) end diff --git a/db/migrate/20180418160205_add_updated_at_to_has_tag_string_tags.rb b/db/migrate/20180418160205_add_updated_at_to_has_tag_string_tags.rb index 79f1c63d8f..e07eccaea0 100644 --- a/db/migrate/20180418160205_add_updated_at_to_has_tag_string_tags.rb +++ b/db/migrate/20180418160205_add_updated_at_to_has_tag_string_tags.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddUpdatedAtToHasTagStringTags < ActiveRecord::Migration[4.2] +class AddUpdatedAtToHasTagStringTags < ActiveRecord::Migration[4.2] def up add_column :has_tag_string_tags, :updated_at, :datetime end diff --git a/db/migrate/20180418160206_add_timestamps_to_acts_as_xapian_jobs.rb b/db/migrate/20180418160206_add_timestamps_to_acts_as_xapian_jobs.rb index 6c40ce32f5..48e68119f9 100644 --- a/db/migrate/20180418160206_add_timestamps_to_acts_as_xapian_jobs.rb +++ b/db/migrate/20180418160206_add_timestamps_to_acts_as_xapian_jobs.rb @@ -1,5 +1,5 @@ # -*- encoding : utf-8 -*- -class AddTimestampsToActsAsXapianJobs < ActiveRecord::Migration[4.2] +class AddTimestampsToActsAsXapianJobs < ActiveRecord::Migration[4.2] def change add_timestamps(:acts_as_xapian_jobs, null: true) end diff --git a/db/migrate/20180801085621_add_closed_at_to_users.rb b/db/migrate/20180801085621_add_closed_at_to_users.rb index d5d7115ea4..c238cd9d0f 100644 --- a/db/migrate/20180801085621_add_closed_at_to_users.rb +++ b/db/migrate/20180801085621_add_closed_at_to_users.rb @@ -1,4 +1,4 @@ -class AddClosedAtToUsers < ActiveRecord::Migration[4.2] +class AddClosedAtToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :closed_at, :timestamp end diff --git a/db/migrate/20181128160243_add_incoming_messages_count_to_info_requests.rb b/db/migrate/20181128160243_add_incoming_messages_count_to_info_requests.rb index 28406f5565..95ce2b0aef 100644 --- a/db/migrate/20181128160243_add_incoming_messages_count_to_info_requests.rb +++ b/db/migrate/20181128160243_add_incoming_messages_count_to_info_requests.rb @@ -1,4 +1,4 @@ -class AddIncomingMessagesCountToInfoRequests < ActiveRecord::Migration[4.2] +class AddIncomingMessagesCountToInfoRequests < ActiveRecord::Migration[4.2] def change add_column :info_requests, :incoming_messages_count, :integer, default: 0 end diff --git a/lib/data_export.rb b/lib/data_export.rb index 341bf0f52b..dc86759b8d 100644 --- a/lib/data_export.rb +++ b/lib/data_export.rb @@ -140,7 +140,7 @@ def self.process_data(filename, display_header, column_data, overrides, query) CSV.open(filename, "wb") do |csv| csv << display_header find_each_record(query) do |model_instance| - line = [] + line = [] # iterate over columns to create an array of data to make a line of csv column_data.each do |attribute| if overrides.key?(attribute) #do we have an override for this column? diff --git a/lib/mail_handler/mail_handler.rb b/lib/mail_handler/mail_handler.rb index e1593755ed..88a005fa20 100644 --- a/lib/mail_handler/mail_handler.rb +++ b/lib/mail_handler/mail_handler.rb @@ -84,7 +84,7 @@ def get_attachment_text_one_file(content_type, body, charset = 'utf-8') :timeout => 1200 } if content_type == 'application/vnd.ms-word' AlaveteliExternalCommand.run("wvText", tempfile.path, tempfile.path + ".txt", - { :memory_limit => 536870912, :timeout => 120 } ) + { :memory_limit => 536870912, :timeout => 120 } ) # Try catdoc if we get into trouble (e.g. for InfoRequestEvent 2701) if not File.exists?(tempfile.path + ".txt") AlaveteliExternalCommand.run("catdoc", tempfile.path, default_params) diff --git a/lib/tasks/graphs.rake b/lib/tasks/graphs.rake index dd302d3810..3401bc85c2 100644 --- a/lib/tasks/graphs.rake +++ b/lib/tasks/graphs.rake @@ -199,15 +199,15 @@ namespace :graphs do state_list = [ {:state => 'waiting_response', :colour => :darkblue}, {:state => 'waiting_clarification', :colour => :lightblue}, - {:state => 'not_held', :colour => :yellow}, - {:state => 'rejected', :colour => :red}, - {:state => 'successful', :colour => :lightgreen}, - {:state => 'partially_successful', :colour => :darkgreen}, - {:state => 'requires_admin', :colour => :cyan}, - {:state => 'gone_postal', :colour => :darkyellow}, - {:state => 'internal_review', :colour => :mauve}, - {:state => 'error_message', :colour => :redbrown}, - {:state => 'user_withdrawn', :colour => :pink} ] + {:state => 'not_held', :colour => :yellow}, + {:state => 'rejected', :colour => :red}, + {:state => 'successful', :colour => :lightgreen}, + {:state => 'partially_successful', :colour => :darkgreen}, + {:state => 'requires_admin', :colour => :cyan}, + {:state => 'gone_postal', :colour => :darkyellow}, + {:state => 'internal_review', :colour => :mauve}, + {:state => 'error_message', :colour => :redbrown}, + {:state => 'user_withdrawn', :colour => :pink} ] options = {:with => "impulses", :linecolor => COLOURS[state_list[0][:colour]], diff --git a/lib/tasks/themes.rake b/lib/tasks/themes.rake index 080b0f8363..65bb667e11 100644 --- a/lib/tasks/themes.rake +++ b/lib/tasks/themes.rake @@ -177,7 +177,7 @@ namespace :themes do missing_templates = [] missing_sections = [] if !template_file - missing_templates << template_file + missing_templates << template_file puts "Missing help template: #{help_template_info[:name]} #{locale}" else contents = File.read(template_file) diff --git a/lib/tasks/translation.rake b/lib/tasks/translation.rake index ddc1c5c08d..2772df84e9 100644 --- a/lib/tasks/translation.rake +++ b/lib/tasks/translation.rake @@ -5,7 +5,7 @@ namespace :translation do include Usage def write_email(email, email_description, output_file) - mail_object = MailHandler.mail_from_raw_email(email.to_s) + mail_object = MailHandler.mail_from_raw_email(email.to_s) output_file.write("\n") output_file.write("Description of email: #{email_description}\n") output_file.write("Subject line: #{mail_object.subject}\n") @@ -92,7 +92,7 @@ namespace :translation do 'fixtures', 'files', 'incoming-request-plain.email')) - response_mail = MailHandler.mail_from_raw_email(content) + response_mail = MailHandler.mail_from_raw_email(content) response_mail.from = "authority@example.com" stopped_responses_email = RequestMailer.stopped_responses(info_request, diff --git a/lib/use_spans_for_errors.rb b/lib/use_spans_for_errors.rb index f1b1cbb95b..053258adf0 100644 --- a/lib/use_spans_for_errors.rb +++ b/lib/use_spans_for_errors.rb @@ -9,4 +9,4 @@ # # See http://dev.rubyonrails.org/ticket/2210 -ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| %(#{html_tag}).html_safe} +ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| %(#{html_tag}).html_safe} diff --git a/lib/xapian_queries.rb b/lib/xapian_queries.rb index ed0413e641..18c57336cb 100644 --- a/lib/xapian_queries.rb +++ b/lib/xapian_queries.rb @@ -34,7 +34,7 @@ def get_status_from_params(params) if params[:latest_status].class == String params[:latest_status] = [params[:latest_status]] end - if params[:latest_status].include?("recent") || params[:latest_status].include?("all") + if params[:latest_status].include?("recent") || params[:latest_status].include?("all") query += " (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)" end if params[:latest_status].include? "successful" diff --git a/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb b/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb index 3ea3dd4d05..e320e4673b 100644 --- a/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb @@ -100,7 +100,7 @@ end context "when the user does not own the embargo" do - let(:other_user) { FactoryBot.create(:pro_user) } + let(:other_user) { FactoryBot.create(:pro_user) } it 'raises a CanCan::AccessDenied error' do expect do diff --git a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb index c08d966805..14430c69d0 100644 --- a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb @@ -188,7 +188,7 @@ def send_request end it 'sends an exception email' do - expected = 'AlaveteliPro::StripeWebhooksController::' \ + expected = 'AlaveteliPro::StripeWebhooksController::' \ 'MissingTypeStripeWebhookError' mail = ActionMailer::Base.deliveries.first expect(mail.subject).to include(expected) diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb index 59453263b0..197c391198 100644 --- a/spec/controllers/general_controller_spec.rb +++ b/spec/controllers/general_controller_spec.rb @@ -327,7 +327,7 @@ it 'should highlight words for a user-only request' do get :search, params: { :combined => "bob/users" } - expect(assigns[:highlight_words]).to eq([/\b(bob)\w*\b/iu, /\b(bob)\b/iu]) + expect(assigns[:highlight_words]).to eq([/\b(bob)\w*\b/iu, /\b(bob)\b/iu]) end it 'should show spelling corrections for a user-only request' do diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index 6e37f23937..c074f493ec 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -662,7 +662,7 @@ def make_request expect(response).to render_template('confirm') deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) expect(deliveries[0].body).to include("not reveal your email") end @@ -679,7 +679,7 @@ def make_request expect(response).to render_template('confirm') deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) expect(deliveries[0].body).to include("No revelaremos") end @@ -696,7 +696,7 @@ def make_request expect(response).to render_template('confirm') deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) # This text may span a line break, depending on the length of the SITE_NAME expect(deliveries[0].body).to match(/when\s+you\s+already\s+have\s+an/) @@ -714,7 +714,7 @@ def make_request expect(response).to render_template('confirm') deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) # This text may span a line break, depending on the length of the SITE_NAME expect(deliveries[0].body).to match(/when\s+you\s+already\s+have\s+an/) @@ -1010,7 +1010,7 @@ def make_request expect(assigns[:signchangeemail].errors[:password]).not_to be_nil deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(0) + expect(deliveries.size).to eq(0) end it "should be an error if old email is wrong, everything else right" do @@ -1033,7 +1033,7 @@ def make_request expect(assigns[:signchangeemail].errors[:old_email]).not_to be_nil deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(0) + expect(deliveries.size).to eq(0) end it "should work even if the old email had a case difference" do @@ -1074,7 +1074,7 @@ def make_request expect(response).to render_template('signchangeemail_confirm') deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) mail = deliveries[0] expect(mail.body).to include("perhaps you, just tried to change their") diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 6e6dd7db0e..ae6e6ca975 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -348,7 +348,7 @@ def do_signin(email, password) expect(ActionMailer::Base.deliveries).not_to be_empty deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) mail = deliveries[0] mail.body.to_s =~ /(http:\/\/.*(\/c\/(.*)))/ mail_url = $1 @@ -382,7 +382,7 @@ def do_signin(email, password) expect(ActionMailer::Base.deliveries).not_to be_empty deliveries = ActionMailer::Base.deliveries - expect(deliveries.size).to eq(1) + expect(deliveries.size).to eq(1) mail = deliveries[0] mail.body.to_s =~ /(http:\/\/.*(\/c\/(.*)))/ mail_url = $1 diff --git a/spec/helpers/admin_users_helper_spec.rb b/spec/helpers/admin_users_helper_spec.rb index 4e53d315bc..a08087868d 100644 --- a/spec/helpers/admin_users_helper_spec.rb +++ b/spec/helpers/admin_users_helper_spec.rb @@ -18,13 +18,13 @@ end it 'adds a banned label if the user is banned' do - user = FactoryBot.create(:user, ban_text: 'Banned') + user = FactoryBot.create(:user, ban_text: 'Banned') html = %q(banned) expect(user_labels(user)).to eq(html) end it 'adds a closed label if the user is banned' do - user = FactoryBot.create(:user, closed_at: Time.zone.now) + user = FactoryBot.create(:user, closed_at: Time.zone.now) html = %q(closed) expect(user_labels(user)).to eq(html) end diff --git a/spec/integration/download_request_spec.rb b/spec/integration/download_request_spec.rb index e5c2b16c4b..ab24ed85eb 100644 --- a/spec/integration/download_request_spec.rb +++ b/spec/integration/download_request_spec.rb @@ -220,7 +220,7 @@ def sleep_and_receive_mail(name, info_request) sleep_and_receive_mail('incoming-request-attachment-unknown-extension.email', info_request) inspect_zip_download(request_owner, info_request) do |zip| - expect(zip.count).to eq(4) # the message plus two "hello-world.txt" files, and the new attachment + expect(zip.count).to eq(4) # the message plus two "hello-world.txt" files, and the new attachment expect(zip.read('3_2_hello.qwglhm')).to match('This is an unusual') end end @@ -438,7 +438,7 @@ def sleep_and_receive_mail(name, info_request) it 'should successfully make a zipfile for an external request' do external_request = FactoryBot.create(:external_request) user = login(FactoryBot.create(:user)) - inspect_zip_download(user, external_request){ |zip| expect(zip.count).to eq(1) } + inspect_zip_download(user, external_request){ |zip| expect(zip.count).to eq(1) } end end diff --git a/spec/integration/localisation_spec.rb b/spec/integration/localisation_spec.rb index 6f8b018b96..33f40439ec 100644 --- a/spec/integration/localisation_spec.rb +++ b/spec/integration/localisation_spec.rb @@ -93,7 +93,7 @@ it 'should generate URLs without a locale prepended' do get '/' - expect(response.body).to match /class="current-locale">English/ + expect(response.body).to match /class="current-locale">English/ expect(response.body).not_to match /#{@default_lang_home_link}/ end @@ -110,7 +110,7 @@ it 'should render the front page in the default language when no locale param is present and the session locale is not the default' do get '/', headers: { :locale => 'es' } - expect(response.body).to match /class="current-locale">English/ + expect(response.body).to match /class="current-locale">English/ end end @@ -123,7 +123,7 @@ it 'should generate URLs with a locale prepended' do get '/' - expect(response.body).to match /class="current-locale">English/ + expect(response.body).to match /class="current-locale">English/ expect(response.body).to match /#{@default_lang_home_link}/ end diff --git a/spec/lib/alaveteli_mail_poller_spec.rb b/spec/lib/alaveteli_mail_poller_spec.rb index 37a45dad4f..3589a907a0 100644 --- a/spec/lib/alaveteli_mail_poller_spec.rb +++ b/spec/lib/alaveteli_mail_poller_spec.rb @@ -69,7 +69,7 @@ it 'sends an exception notification' do poller.poll_for_incoming - notification = ActionMailer::Base.deliveries.first + notification = ActionMailer::Base.deliveries.first expect(notification.subject). to eq('[ERROR] (Net::POPError) "Error code"') end @@ -86,7 +86,7 @@ it 'sends an exception notification' do poller.poll_for_incoming - notification = ActionMailer::Base.deliveries.first + notification = ActionMailer::Base.deliveries.first expect(notification.subject). to eq('[ERROR] (Net::POPError) "Error code"') end @@ -150,7 +150,7 @@ it 'sends an exception notification' do poller.poll_for_incoming - notification = ActionMailer::Base.deliveries.first + notification = ActionMailer::Base.deliveries.first expect(notification.subject). to eq('[ERROR] (ActiveRecord::StatementInvalid) "Deadlock"') end @@ -271,7 +271,7 @@ it 'sends an exception notification' do expect { poller.poll_for_incoming }.to_not raise_error - notification = ActionMailer::Base.deliveries.first + notification = ActionMailer::Base.deliveries.first expect(notification.subject). to eq('[ERROR] (Timeout::Error) "execution expired"') end diff --git a/spec/lib/alaveteli_rate_limiter/window_spec.rb b/spec/lib/alaveteli_rate_limiter/window_spec.rb index 1ff50de313..855be854f6 100644 --- a/spec/lib/alaveteli_rate_limiter/window_spec.rb +++ b/spec/lib/alaveteli_rate_limiter/window_spec.rb @@ -12,12 +12,12 @@ end it 'requires a :value key' do - hash = { :unit => :day } + hash = { :unit => :day } expect { described_class.from_hash(hash) }.to raise_error(KeyError) end it 'requires a :unit key' do - hash = { :value => 3 } + hash = { :value => 3 } expect { described_class.from_hash(hash) }.to raise_error(KeyError) end diff --git a/spec/lib/data_export_spec.rb b/spec/lib/data_export_spec.rb index bd7c65f395..b13d4b3640 100644 --- a/spec/lib/data_export_spec.rb +++ b/spec/lib/data_export_spec.rb @@ -156,7 +156,7 @@ let(:cut_off) { Date.today + 1 } it "includes eligible attachments" do - incoming = FactoryBot.create(:incoming_message) + incoming = FactoryBot.create(:incoming_message) attachment = FactoryBot.create(:html_attachment, :incoming_message => incoming) exportable = described_class.exportable_foi_attachments(cut_off) @@ -165,7 +165,7 @@ end it "does not include attachments of hidden messages" do - incoming = FactoryBot.create(:incoming_message, :prominence => 'hidden') + incoming = FactoryBot.create(:incoming_message, :prominence => 'hidden') attachment = FactoryBot.create(:html_attachment, :incoming_message => incoming) exportable = described_class.exportable_foi_attachments(cut_off) diff --git a/spec/models/alaveteli_pro/embargo_spec.rb b/spec/models/alaveteli_pro/embargo_spec.rb index a8bf133f5e..fc08f5377c 100644 --- a/spec/models/alaveteli_pro/embargo_spec.rb +++ b/spec/models/alaveteli_pro/embargo_spec.rb @@ -230,7 +230,7 @@ info_request = FactoryBot.create(:use_notifications_request) embargo = FactoryBot.create(:expiring_embargo, info_request: info_request) - embargo.update_attribute(:publish_at, Time.zone.today - 4.months) + embargo.update_attribute(:publish_at, Time.zone.today - 4.months) AlaveteliPro::Embargo.expire_publishable expect(Notification.count).to eq 1 end diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb index 5cc14e1414..c130eb0727 100644 --- a/spec/models/incoming_message_spec.rb +++ b/spec/models/incoming_message_spec.rb @@ -862,7 +862,7 @@ def populate_raw_email(fixture) im.extract_attachments! expect(im.get_attachments_for_display.map(&:display_filename)).to eq([ - 'test.html', # picks HTML rather than text by default, as likely to render better + 'test.html', # picks HTML rather than text by default, as likely to render better 'attach.txt', ]) end diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 8e534e59c2..e09120e523 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -2119,7 +2119,7 @@ end it 'returns the cache path for any other locales' do - other_locale_path = File.join(Rails.root, 'cache', 'views', 'es', 'request', '101', '101') + other_locale_path = File.join(Rails.root, 'cache', 'views', 'es', 'request', '101', '101') expect(@info_request.foi_fragment_cache_directories.include?(other_locale_path)).to eq(true) end @@ -2982,7 +2982,7 @@ def create_old_unclassified_holding_pen end - describe 'when generating json for the api' do + describe 'when generating json for the api' do before do @user = mock_model(User, :json_for_api => { :id => 20, diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index 4f9e29a7fc..da15081e7f 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -910,7 +910,7 @@ end - describe 'when generating json for the api' do + describe 'when generating json for the api' do let(:public_body) do FactoryBot.create(:public_body, diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 25dcf80a74..9c803ac861 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -89,7 +89,7 @@ expect(@user.name).to eq('Some Name') end - describe 'if user has been banned' do + describe 'if user has been banned' do before do @user.ban_text = "Naughty user" @@ -343,7 +343,7 @@ def create_user(options = {}) @user.save! end - it 'should mark the model for reindexing in xapian if the no_xapian_reindex flag is not set' do + it 'should mark the model for reindexing in xapian if the no_xapian_reindex flag is not set' do @user.name = 'Mr. Second' @user.password = 'insecurepassword' @user.email = 'reasonable@localhost' From df50c2ae1603d31a98ceb8232fa0d07b80b4048e Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 09:40:32 +0100 Subject: [PATCH 004/114] Correct indentation consistency Mostly done by auto correcting but needed to check manually and fix some issues. Command: `bundle exec rubocop --only Layout/IndentationConsistency --auto-correct` --- app/controllers/public_body_controller.rb | 60 +++---- app/models/public_body.rb | 18 +-- ..._reject_incoming_at_mta_to_info_request.rb | 2 +- lib/alaveteli_gettext/fuzzy_cleaner.rb | 2 +- lib/tasks/temp.rake | 2 +- lib/tasks/themes.rake | 2 +- lib/world_foi_websites.rb | 56 +++---- .../admin_comment_controller_spec.rb | 8 +- ..._public_body_categories_controller_spec.rb | 8 +- .../alaveteli_pro/embargo_controller_spec.rb | 2 +- .../embargo_extensions_controller_spec.rb | 2 +- spec/controllers/followups_controller_spec.rb | 2 +- spec/controllers/reports_controller_spec.rb | 148 +++++++++--------- spec/controllers/request_controller_spec.rb | 8 +- spec/controllers/track_controller_spec.rb | 3 +- spec/integration/admin_spec.rb | 2 +- .../alaveteli_pro/batch_request_spec.rb | 2 +- spec/integration/classify_request_spec.rb | 4 +- .../alaveteli_pro/account_mailer_spec.rb | 10 +- spec/models/ability_spec.rb | 12 +- spec/models/info_request_spec.rb | 4 +- .../mail_server_log/delivery_status_spec.rb | 12 +- 22 files changed, 185 insertions(+), 184 deletions(-) diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 2144556523..78a21b8def 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -128,40 +128,40 @@ def list with_query(params[:public_body_query], @tag). paginate(page: params[:page], per_page: 100) - @description = - if @tag == 'all' - n_('Found {{count}} public authority', - 'Found {{count}} public authorities', - @public_bodies.total_entries, - :count => @public_bodies.total_entries) - elsif @tag.size == 1 - n_('Found {{count}} public authority beginning with ' \ - '‘{{first_letter}}’', - 'Found {{count}} public authorities beginning with ' \ - '‘{{first_letter}}’', - @public_bodies.total_entries, - :count => @public_bodies.total_entries, - :first_letter => @tag) - else - category_name = PublicBodyCategory.get.by_tag[@tag] - if category_name.nil? - n_('Found {{count}} public authority matching the tag ' \ - '‘{{tag_name}}’', - 'Found {{count}} public authorities matching the tag ' \ - '‘{{tag_name}}’', + @description = + if @tag == 'all' + n_('Found {{count}} public authority', + 'Found {{count}} public authorities', @public_bodies.total_entries, - :count => @public_bodies.total_entries, - :tag_name => @tag) - else - n_('Found {{count}} public authority in the category ' \ - '‘{{category_name}}’', - 'Found {{count}} public authorities in the category ' \ - '‘{{category_name}}’', + :count => @public_bodies.total_entries) + elsif @tag.size == 1 + n_('Found {{count}} public authority beginning with ' \ + '‘{{first_letter}}’', + 'Found {{count}} public authorities beginning with ' \ + '‘{{first_letter}}’', @public_bodies.total_entries, :count => @public_bodies.total_entries, - :category_name => category_name) + :first_letter => @tag) + else + category_name = PublicBodyCategory.get.by_tag[@tag] + if category_name.nil? + n_('Found {{count}} public authority matching the tag ' \ + '‘{{tag_name}}’', + 'Found {{count}} public authorities matching the tag ' \ + '‘{{tag_name}}’', + @public_bodies.total_entries, + :count => @public_bodies.total_entries, + :tag_name => @tag) + else + n_('Found {{count}} public authority in the category ' \ + '‘{{category_name}}’', + 'Found {{count}} public authorities in the category ' \ + '‘{{category_name}}’', + @public_bodies.total_entries, + :count => @public_bodies.total_entries, + :category_name => category_name) + end end - end respond_to do |format| format.html { render :template => 'public_body/list' } diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 46c0288d3a..32b647604b 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -692,8 +692,8 @@ def self.where_clause_for_stats(minimum_requests, total_column) # sub-select to find the IDs of those public bodies. test_tagged_query = "SELECT model_id FROM has_tag_string_tags" \ " WHERE model = 'PublicBody' AND name = 'test'" - "#{total_column} >= #{minimum_requests} " \ - "AND id NOT IN (#{test_tagged_query})" + "#{total_column} >= #{minimum_requests} " \ + "AND id NOT IN (#{test_tagged_query})" end # Return data for the 'n' public bodies with the highest (or @@ -947,12 +947,12 @@ def self.get_public_body_list_translated_condition(table, has_first_letter=false result = "(upper(#{table}.name) LIKE upper(:query)" \ " OR upper(#{table}.notes) LIKE upper(:query)" \ " OR upper(#{table}.short_name) LIKE upper(:query))" - if has_first_letter - result += " AND #{table}.first_letter = :first_letter" - end - if locale - result += " AND #{table}.locale = :locale" - end - result + if has_first_letter + result += " AND #{table}.first_letter = :first_letter" + end + if locale + result += " AND #{table}.locale = :locale" + end + result end end diff --git a/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb b/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb index ca8621f2ab..c72023f2ff 100644 --- a/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb +++ b/db/migrate/20160602143125_add_reject_incoming_at_mta_to_info_request.rb @@ -1,6 +1,6 @@ # -*- encoding : utf-8 -*- class AddRejectIncomingAtMtaToInfoRequest < ActiveRecord::Migration[4.2] # 3.2 - def up + def up add_column :info_requests, :reject_incoming_at_mta, :boolean, :default => false, :null => false end diff --git a/lib/alaveteli_gettext/fuzzy_cleaner.rb b/lib/alaveteli_gettext/fuzzy_cleaner.rb index a388739e00..2a2b038dcf 100644 --- a/lib/alaveteli_gettext/fuzzy_cleaner.rb +++ b/lib/alaveteli_gettext/fuzzy_cleaner.rb @@ -11,7 +11,7 @@ def clean_po(input) # one line msgstr if /^msgstr "(.+)"/.match(lines[index+1]) lines[index+1] = "msgstr \"\"" - lines.delete_at(index-1) + lines.delete_at(index-1) end # multiline msgstr if /^msgstr ""/.match(lines[index+1]) diff --git a/lib/tasks/temp.rake b/lib/tasks/temp.rake index 3819334302..9355273547 100644 --- a/lib/tasks/temp.rake +++ b/lib/tasks/temp.rake @@ -352,7 +352,7 @@ namespace :temp do !incoming_message.cached_main_body_text_folded.valid_encoding?) || (incoming_message.cached_main_body_text_unfolded && !incoming_message.cached_main_body_text_unfolded.valid_encoding?) - puts "Bad encoding in IncomingMessage cached fields, :id #{incoming_message.id} " + puts "Bad encoding in IncomingMessage cached fields, :id #{incoming_message.id} " unless dryrun incoming_message.clear_in_database_caches! end diff --git a/lib/tasks/themes.rake b/lib/tasks/themes.rake index 65bb667e11..d487bec2c7 100644 --- a/lib/tasks/themes.rake +++ b/lib/tasks/themes.rake @@ -198,7 +198,7 @@ namespace :themes do desc "Check that all help sections referred to in the application are present in theme" task :check_help_sections => :environment do - intro_message = <<-EOF + intro_message = <<-EOF Checking that all help templates linked to from Alaveteli are present in the theme, and that all sections linked to from Alaveteli are present in the templates. For diff --git a/lib/world_foi_websites.rb b/lib/world_foi_websites.rb index a61f95c668..45029520cc 100644 --- a/lib/world_foi_websites.rb +++ b/lib/world_foi_websites.rb @@ -1,33 +1,33 @@ # -*- encoding : utf-8 -*- class WorldFOIWebsites - EU_COUNTRIES = { 'BE' => 'Belgium', - 'BG' => 'Bulgaria', - 'CZ' => 'Czech Republic', - 'DK' => 'Denmark', - 'DE' => 'Germany', - 'EE' => 'Estonia', - 'IE' => 'Ireland', - 'GR' => 'Greece', - 'ES' => 'Spain', - 'FR' => 'France', - 'HR' => 'Croatia', - 'IT' => 'Italy', - 'CY' => 'Cyprus', - 'LV' => 'Latvia', - 'LT' => 'Lithuania', - 'LU' => 'Luxembourg', - 'HU' => 'Hungary', - 'MT' => 'Malta', - 'NL' => 'Netherlands', - 'AT' => 'Austria', - 'PL' => 'Poland', - 'PT' => 'Portugal', - 'RO' => 'Romania', - 'SI' => 'Slovenia', - 'SK' => 'Slovakia', - 'FI' => 'Finland', - 'SE' => 'Sweden', - 'GB' => 'United Kingdom' }.freeze + EU_COUNTRIES = { 'BE' => 'Belgium', + 'BG' => 'Bulgaria', + 'CZ' => 'Czech Republic', + 'DK' => 'Denmark', + 'DE' => 'Germany', + 'EE' => 'Estonia', + 'IE' => 'Ireland', + 'GR' => 'Greece', + 'ES' => 'Spain', + 'FR' => 'France', + 'HR' => 'Croatia', + 'IT' => 'Italy', + 'CY' => 'Cyprus', + 'LV' => 'Latvia', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'HU' => 'Hungary', + 'MT' => 'Malta', + 'NL' => 'Netherlands', + 'AT' => 'Austria', + 'PL' => 'Poland', + 'PT' => 'Portugal', + 'RO' => 'Romania', + 'SI' => 'Slovenia', + 'SK' => 'Slovakia', + 'FI' => 'Finland', + 'SE' => 'Sweden', + 'GB' => 'United Kingdom' }.freeze def self.world_foi_websites world_foi_websites = [ diff --git a/spec/controllers/admin_comment_controller_spec.rb b/spec/controllers/admin_comment_controller_spec.rb index 56e71ece19..6e851d7b37 100644 --- a/spec/controllers/admin_comment_controller_spec.rb +++ b/spec/controllers/admin_comment_controller_spec.rb @@ -129,10 +129,10 @@ end describe 'PUT update' do - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:comment){ FactoryBot.create(:comment) } - let(:atts){ FactoryBot.attributes_for(:comment, :body => 'I am new') } + let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:admin_user){ FactoryBot.create(:admin_user) } + let(:comment){ FactoryBot.create(:comment) } + let(:atts){ FactoryBot.attributes_for(:comment, :body => 'I am new') } context 'on valid data submission' do diff --git a/spec/controllers/admin_public_body_categories_controller_spec.rb b/spec/controllers/admin_public_body_categories_controller_spec.rb index 327bd19b8e..4e97268364 100644 --- a/spec/controllers/admin_public_body_categories_controller_spec.rb +++ b/spec/controllers/admin_public_body_categories_controller_spec.rb @@ -489,9 +489,9 @@ } } - category = PublicBodyCategory.find(@category.id) - expect(category.title(:es)).to eq('Renamed') - expect(category.title(:en)).to eq(@category.title(:en)) + category = PublicBodyCategory.find(@category.id) + expect(category.title(:es)).to eq('Renamed') + expect(category.title(:en)).to eq(@category.title(:en)) end it 'adds a new translation' do @@ -615,7 +615,7 @@ } } - expect(response).to redirect_to(edit_admin_category_path(@category)) + expect(response).to redirect_to(edit_admin_category_path(@category)) end end diff --git a/spec/controllers/alaveteli_pro/embargo_controller_spec.rb b/spec/controllers/alaveteli_pro/embargo_controller_spec.rb index c2ffb960bb..8efd1de8f9 100644 --- a/spec/controllers/alaveteli_pro/embargo_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/embargo_controller_spec.rb @@ -320,7 +320,7 @@ it "redirects to that request, not the batch" do expected_path = show_alaveteli_pro_request_path( url_title: info_request_batch.info_requests.first.url_title) - expect(response).to redirect_to(expected_path) + expect(response).to redirect_to(expected_path) end end end diff --git a/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb b/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb index e320e4673b..264b6d77df 100644 --- a/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/embargo_extensions_controller_spec.rb @@ -341,7 +341,7 @@ it "redirects to that request, not the batch" do expected_path = show_alaveteli_pro_request_path( url_title: info_request_batch.info_requests.first.url_title) - expect(response).to redirect_to(expected_path) + expect(response).to redirect_to(expected_path) end end end diff --git a/spec/controllers/followups_controller_spec.rb b/spec/controllers/followups_controller_spec.rb index 64283e9921..387a161ff3 100644 --- a/spec/controllers/followups_controller_spec.rb +++ b/spec/controllers/followups_controller_spec.rb @@ -75,7 +75,7 @@ expected_reason = "To send a follow up message to #{request.public_body.name}" get :new, params: { :request_id => request.id, :incoming_message_id => message_id } - expect(get_last_post_redirect.reason_params[:web]).to eq(expected_reason) + expect(get_last_post_redirect.reason_params[:web]).to eq(expected_reason) end it "calls the message a reply if there is no incoming message" do diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb index 707696f2a9..bda6b39637 100644 --- a/spec/controllers/reports_controller_spec.rb +++ b/spec/controllers/reports_controller_spec.rb @@ -166,7 +166,7 @@ end - context "when reporting a comment (logged in)" do + context "when reporting a comment (logged in)" do before do session[:user_id] = user.id end @@ -228,79 +228,79 @@ end it "marks the comment as having been reported" do - post :create, params: { - :request_id => info_request.url_title, - :comment_id => comment.id, - :reason => "my reason" - } - - comment.reload - expect(comment.attention_requested).to eq(true) - end - - it "does not mark the parent request as having been reported" do - post :create, params: { - :request_id => info_request.url_title, - :comment_id => comment.id, - :reason => "my reason" - } - - info_request.reload - expect(info_request.attention_requested).to eq(false) - expect(info_request.described_state).to_not eq("attention_requested") - end - - it "sends an email alerting admins to the report" do - post :create, params: { - :request_id => info_request.url_title, - :comment_id => comment.id, - :reason => "my reason", - :message => "It's just not" - } - deliveries = ActionMailer::Base.deliveries - - expect(deliveries.size).to eq(1) - mail = deliveries[0] - - expect(mail.subject).to match(/requires admin/) - expect(mail.header['Reply-To'].to_s).to include(user.email) - expect(mail.body).to include(user.name) - - expect(mail.body) - .to include("Reason: my reason\n\nIt's just not") - - expect(mail.body) - .to include("The user wishes to draw attention to the comment: " \ - "#{comment_url(comment)} "\ - "\nadmin: #{edit_admin_comment_url(comment)}") - end - - it "informs the user the comment has been reported" do - expected = "This annotation has been reported for " \ - "administrator attention" - - post :create, params: { - :request_id => info_request.url_title, - :comment_id => comment.id, - :reason => "my reason", - :message => "It's just not" - } - - expect(flash[:notice]).to eq(expected) - end - - it "redirects to the parent info_request page" do - post :create, params: { - :request_id => info_request.url_title, - :comment_id => comment.id, - :reason => "my reason", - :message => "It's just not" - } - - expect(response) - .to redirect_to show_request_path(:url_title => - info_request.url_title) - end + post :create, params: { + :request_id => info_request.url_title, + :comment_id => comment.id, + :reason => "my reason" + } + + comment.reload + expect(comment.attention_requested).to eq(true) + end + + it "does not mark the parent request as having been reported" do + post :create, params: { + :request_id => info_request.url_title, + :comment_id => comment.id, + :reason => "my reason" + } + + info_request.reload + expect(info_request.attention_requested).to eq(false) + expect(info_request.described_state).to_not eq("attention_requested") + end + + it "sends an email alerting admins to the report" do + post :create, params: { + :request_id => info_request.url_title, + :comment_id => comment.id, + :reason => "my reason", + :message => "It's just not" + } + deliveries = ActionMailer::Base.deliveries + + expect(deliveries.size).to eq(1) + mail = deliveries[0] + + expect(mail.subject).to match(/requires admin/) + expect(mail.header['Reply-To'].to_s).to include(user.email) + expect(mail.body).to include(user.name) + + expect(mail.body) + .to include("Reason: my reason\n\nIt's just not") + + expect(mail.body) + .to include("The user wishes to draw attention to the comment: " \ + "#{comment_url(comment)} "\ + "\nadmin: #{edit_admin_comment_url(comment)}") + end + + it "informs the user the comment has been reported" do + expected = "This annotation has been reported for " \ + "administrator attention" + + post :create, params: { + :request_id => info_request.url_title, + :comment_id => comment.id, + :reason => "my reason", + :message => "It's just not" + } + + expect(flash[:notice]).to eq(expected) + end + + it "redirects to the parent info_request page" do + post :create, params: { + :request_id => info_request.url_title, + :comment_id => comment.id, + :reason => "my reason", + :message => "It's just not" + } + + expect(response) + .to redirect_to show_request_path(:url_title => + info_request.url_title) + end end diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 530695bdd9..b4615a5542 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -3381,10 +3381,10 @@ def make_request end it 'assigns the last info request event id to the view' do - get :describe_state_message, params: { - :url_title => info_request.url_title, - :described_state => 'error_message' - } + get :describe_state_message, params: { + :url_title => info_request.url_title, + :described_state => 'error_message' + } expect(assigns[:last_info_request_event_id]) .to eq info_request.last_event_id_needing_description end diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb index c1613bb1fa..24b4d44976 100644 --- a/spec/controllers/track_controller_spec.rb +++ b/spec/controllers/track_controller_spec.rb @@ -110,7 +110,8 @@ expect(assigns[:xapian_object].results[2][:model]) .to eq(info_request_events(:useless_outgoing_message_event)) end - it "should get JSON version of the feed" do + + it "should get JSON version of the feed" do track_thing = track_things(:track_fancy_dog_request) get :track_request, params: { diff --git a/spec/integration/admin_spec.rb b/spec/integration/admin_spec.rb index b69c141309..6d2870f585 100644 --- a/spec/integration/admin_spec.rb +++ b/spec/integration/admin_spec.rb @@ -161,7 +161,7 @@ url = confirm_url(PostRedirect.last.email_token) - message = "Send \"#{authority_name}\" <#{authority_email}> " + message = "Send \"#{authority_name}\" <#{authority_email}> " \ "this URL: #{url} - it will log them in and let " \ "them upload a response to this request." diff --git a/spec/integration/alaveteli_pro/batch_request_spec.rb b/spec/integration/alaveteli_pro/batch_request_spec.rb index 439d54b6c5..d818f3949b 100644 --- a/spec/integration/alaveteli_pro/batch_request_spec.rb +++ b/spec/integration/alaveteli_pro/batch_request_spec.rb @@ -292,7 +292,7 @@ def search_results it "supplies a default embargo when creating a new batch request" do using_pro_session(pro_user_session) do start_batch_request - expect(page).to have_select("Privacy", selected: "3 Months") + expect(page).to have_select("Privacy", selected: "3 Months") end end diff --git a/spec/integration/classify_request_spec.rb b/spec/integration/classify_request_spec.rb index 8d23cd511e..b86e004ad0 100644 --- a/spec/integration/classify_request_spec.rb +++ b/spec/integration/classify_request_spec.rb @@ -235,7 +235,7 @@ "what you did." # redirect and receive thank you message expect(page).to have_content(message) - expect(page).to_not have_link('make a donation') + expect(page).to_not have_link('make a donation') end end @@ -259,7 +259,7 @@ using_session(login(user)) do classify_request(info_request, classification) message = "We're glad you got all the information that you wanted." - unexpected = "please come back and add an annotation" + unexpected = "please come back and add an annotation" # redirect and receive thank you message expect(page).to have_content(message) expect(page).to_not have_content(unexpected) diff --git a/spec/mailers/alaveteli_pro/account_mailer_spec.rb b/spec/mailers/alaveteli_pro/account_mailer_spec.rb index 7c6e69b553..db15e9a472 100644 --- a/spec/mailers/alaveteli_pro/account_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/account_mailer_spec.rb @@ -12,11 +12,11 @@ offer_code: 'SPECIAL') end - before do - @message = AlaveteliPro::AccountMailer. - account_request(account_request). - message - end + before do + @message = AlaveteliPro::AccountMailer. + account_request(account_request). + message + end it "sends the email to the pro contact address" do expect(@message.to).to eq [AlaveteliConfiguration.pro_contact_email] diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 9cc9970e18..0ac5096048 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -842,12 +842,12 @@ end end - it 'does not allow them to login as themselves' do - with_feature_enabled(:alaveteli_pro) do - ability = Ability.new(pro_user) - expect(ability).not_to be_able_to(:login_as, pro_user) - end - end + it 'does not allow them to login as themselves' do + with_feature_enabled(:alaveteli_pro) do + ability = Ability.new(pro_user) + expect(ability).not_to be_able_to(:login_as, pro_user) + end + end it 'does not allow user with no roles to login as them' do with_feature_enabled(:alaveteli_pro) do diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index e09120e523..7a9f8da082 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -4116,8 +4116,8 @@ def email_and_raw_email(opts = {}) followup_event = info_request. info_request_events.reload. detect{ |e| e.event_type == 'followup_sent'} - expect(info_request.last_event_forming_initial_request) - .to eq followup_event + expect(info_request.last_event_forming_initial_request) + .to eq followup_event end it 'raises an error if the request has never been sent' do diff --git a/spec/models/mail_server_log/delivery_status_spec.rb b/spec/models/mail_server_log/delivery_status_spec.rb index d712135a64..545004b8b6 100644 --- a/spec/models/mail_server_log/delivery_status_spec.rb +++ b/spec/models/mail_server_log/delivery_status_spec.rb @@ -74,12 +74,12 @@ :sent].map { |s| described_class.new(s) } end - let(:sorted) do - [:unknown, - :failed, - :sent, - :delivered] - end + let(:sorted) do + [:unknown, + :failed, + :sent, + :delivered] + end it { expect(statuses.sort.map(&:to_sym)).to eq(sorted) } it { expect(statuses.sort { |a,b| b <=> a }.map(&:to_sym)).to eq(sorted.reverse) } From 9d0b3d18f86773f5b6c70ffad46badb8119f3094 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 09:49:56 +0100 Subject: [PATCH 005/114] Correct indent assignment Command: `bundle exec rubocop --only Layout/IndentAssignment --auto-correct` --- .../admin_public_body_controller.rb | 6 +++--- app/controllers/widgets_controller.rb | 18 +++++++++--------- .../concerns/alaveteli_pro/phase_counts.rb | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 64958dc513..9f9fd51e45 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -80,9 +80,9 @@ def edit if @change_request @change_request_user_response = - render_to_string( - template: 'admin_public_body_change_requests/update_accepted', - formats: [:txt]) + render_to_string( + template: 'admin_public_body_change_requests/update_accepted', + formats: [:txt]) @public_body.request_email = @change_request.public_body_email @public_body.last_edit_comment = @change_request.comment_for_public_body else diff --git a/app/controllers/widgets_controller.rb b/app/controllers/widgets_controller.rb index 6a293d27bc..24aa04bf61 100644 --- a/app/controllers/widgets_controller.rb +++ b/app/controllers/widgets_controller.rb @@ -18,17 +18,17 @@ def show @user_owns_request = @info_request.user && @info_request.user == @user @existing_track = - if @user - TrackThing.find_existing(@user, @track_thing) - end + if @user + TrackThing.find_existing(@user, @track_thing) + end @existing_vote = - unless @existing_track - @info_request. - widget_votes. - where(:cookie => cookies[:widget_vote]). - any? - end + unless @existing_track + @info_request. + widget_votes. + where(:cookie => cookies[:widget_vote]). + any? + end render :action => 'show', :layout => false end diff --git a/app/models/concerns/alaveteli_pro/phase_counts.rb b/app/models/concerns/alaveteli_pro/phase_counts.rb index 17a2208e50..e62527f5fb 100644 --- a/app/models/concerns/alaveteli_pro/phase_counts.rb +++ b/app/models/concerns/alaveteli_pro/phase_counts.rb @@ -14,11 +14,11 @@ def phase_counts! # Calculate the phase totals from the request_summary_categories raw_counts = - request_summaries. - joins(:request_summary_categories). - references(:request_summary_categories). - group("request_summary_categories.slug"). - count("request_summary_categories.id") + request_summaries. + joins(:request_summary_categories). + references(:request_summary_categories). + group("request_summary_categories.slug"). + count("request_summary_categories.id") raw_counts['not_drafts'] = request_summaries.not_category(:draft).count @phase_counts = From 10505a6f510b9732d2d20005c42fe39ecfabcb85 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:05:30 +0100 Subject: [PATCH 006/114] Correct multiline array brace layout Mostly done by auto correcting but needed to check manually and fix some issues. Command: `bundle exec rubocop --only Layout/MultilineArrayBraceLayout --auto-correct` --- app/controllers/admin_general_controller.rb | 9 +++++---- app/controllers/api_controller.rb | 6 ++++-- app/models/alaveteli_pro/request_filter.rb | 5 +++-- app/models/comment.rb | 3 +-- app/models/info_request/state.rb | 3 ++- app/models/info_request_event.rb | 3 +-- lib/tasks/export.rake | 9 +++------ lib/tasks/graphs.rake | 3 ++- lib/tasks/temp.rake | 6 ++++-- lib/tasks/themes.rake | 9 +++------ spec/controllers/api_controller_spec.rb | 9 ++++++--- spec/controllers/request_controller_spec.rb | 6 ++++-- 12 files changed, 38 insertions(+), 33 deletions(-) diff --git a/app/controllers/admin_general_controller.rb b/app/controllers/admin_general_controller.rb index 592621ec23..7215e7b8d7 100644 --- a/app/controllers/admin_general_controller.rb +++ b/app/controllers/admin_general_controller.rb @@ -75,10 +75,11 @@ def index find_in_state('attention_requested'). embargoed - @embargoed_request_tasks = [ @embargoed_requires_admin_requests, - @embargoed_error_message_requests, - @embargoed_attention_requests, - ].any?{ |to_do_list| ! to_do_list.empty? } + @embargoed_request_tasks = [ + @embargoed_requires_admin_requests, + @embargoed_error_message_requests, + @embargoed_attention_requests, + ].any?{ |to_do_list| ! to_do_list.empty? } @embargoed_attention_comments = Comment. where(:attention_requested => true). diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 92d0187e2d..e7f7efc3fb 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -209,7 +209,8 @@ def body_request_events since_date = Date.strptime(since_date_str, "%Y-%m-%d") rescue ArgumentError render :json => {"errors" => [ - "Parameter since_date must be in format yyyy-mm-dd (not '#{since_date_str}')" ] }, + "Parameter since_date must be in format yyyy-mm-dd (not '#{since_date_str}')" + ] }, :status => 500 return end @@ -223,7 +224,8 @@ def body_request_events event = InfoRequestEvent.find(since_event_id) rescue ActiveRecord::RecordNotFound render :json => {"errors" => [ - "Event ID #{since_event_id} not found" ] }, + "Event ID #{since_event_id} not found" + ] }, :status => 500 return end diff --git a/app/models/alaveteli_pro/request_filter.rb b/app/models/alaveteli_pro/request_filter.rb index 188b1fec75..b1fec8c2f3 100644 --- a/app/models/alaveteli_pro/request_filter.rb +++ b/app/models/alaveteli_pro/request_filter.rb @@ -103,7 +103,8 @@ def order_value end def default_filters - [ { :param => nil, + [ + { :param => nil, :value => nil, :label => _('all requests'), :capital_label => _('All requests') }, @@ -116,7 +117,7 @@ def default_filters :label => _('requests that will be made public soon'), :capital_label => _('Requests that will be made public soon') } - ] + ] end def phase_filters diff --git a/app/models/comment.rb b/app/models/comment.rb index d28614dffb..2aae063d81 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -140,8 +140,7 @@ def for_admin_event_column(event) def report_reasons [_("Annotation contains defamatory material"), _("Annotation contains personal information"), - _("Vexatious annotation") - ] + _("Vexatious annotation")] end # Report this comment for administrator attention diff --git a/app/models/info_request/state.rb b/app/models/info_request/state.rb index bd784e7bd7..8c630ee5c1 100644 --- a/app/models/info_request/state.rb +++ b/app/models/info_request/state.rb @@ -59,7 +59,8 @@ def self.short_description(state) end def self.phases - [ { capital_label: _('Awaiting response'), + [ + { capital_label: _('Awaiting response'), label: _('awaiting response'), scope: :awaiting_response, param: 'awaiting-response' }, diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index ae540e3140..c93b7dd3a4 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -120,8 +120,7 @@ def must_be_valid_state [ :waiting_classification, 'W', "waiting_classification" ], [ :filetype, 'T', "filetype" ], [ :tags, 'U', "tag" ], - [ :request_public_body_tags, 'X', "request_public_body_tag" ] - ], + [ :request_public_body_tags, 'X', "request_public_body_tag" ] ], :if => :indexed_by_search?, :eager_load => [ :outgoing_message, :comment, { :info_request => [ :user, :public_body, :censor_rules ] } ] diff --git a/lib/tasks/export.rake b/lib/tasks/export.rake index a268eea254..a4fe2b84fa 100644 --- a/lib/tasks/export.rake +++ b/lib/tasks/export.rake @@ -88,8 +88,7 @@ namespace :export do "track_things_count", "request_classifications_count", "public_body_change_requests_count", - "info_request_batches_count", - ], + "info_request_batches_count"], override = { "name" => DataExport.gender_lambda, }, @@ -113,8 +112,7 @@ namespace :export do "url_title", "law_used", "last_public_response_at", - "info_request_batch_id" - ]) + "info_request_batch_id"]) DataExport.csv_export(InfoRequestBatch, to_run, @@ -160,8 +158,7 @@ namespace :export do "message_type", "subject", "last_sent_at", - "incoming_message_followup_id" - ], + "incoming_message_followup_id"], override = { "body" => DataExport.name_censor_lambda('body'), }) diff --git a/lib/tasks/graphs.rake b/lib/tasks/graphs.rake index 3401bc85c2..27e6dd2c54 100644 --- a/lib/tasks/graphs.rake +++ b/lib/tasks/graphs.rake @@ -71,7 +71,8 @@ namespace :graphs do # start plotting the data from largest to smallest so # that the shorter bars overlay the taller bars - state_list = [ { + state_list = [ + { :title => "users each day ... who registered", :colour => :lightblue }, diff --git a/lib/tasks/temp.rake b/lib/tasks/temp.rake index 9355273547..783d1a0a90 100644 --- a/lib/tasks/temp.rake +++ b/lib/tasks/temp.rake @@ -124,7 +124,8 @@ namespace :temp do desc 'Audit cached zip download files with censor rules' task :audit_cached_zip_downloads_with_censor_rules => :environment do - puts [ "Info Request ID", + puts [ + "Info Request ID", "URL Title", "Censor rule IDs", "Censor rule patterns", @@ -165,7 +166,8 @@ namespace :temp do cached_types << :public end end - puts [ info_request.id, + puts [ + info_request.id, info_request.url_title, info_request.applicable_censor_rules.map{ |rule| rule.id }.join(","), info_request.applicable_censor_rules.map{ |rule| rule.text }.join(","), diff --git a/lib/tasks/themes.rake b/lib/tasks/themes.rake index d487bec2c7..c7a4b7ac15 100644 --- a/lib/tasks/themes.rake +++ b/lib/tasks/themes.rake @@ -236,18 +236,15 @@ EOF 'full_address', 'postal_answer', 'public_request', - 'real_name' - ]}, + 'real_name']}, {:name => 'requesting', :sections => ['focused', 'data_protection', 'missing_body', - 'quickly_response', - ]}, + 'quickly_response',]}, {:name => 'unhappy', :sections => ['internal_review', - 'other_means' - ]}, + 'other_means']}, {:name => '_why_they_should_reply_by_email', :sections => []}] diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb index 514a62bd54..7675537c62 100644 --- a/spec/controllers/api_controller_spec.rb +++ b/spec/controllers/api_controller_spec.rb @@ -229,7 +229,8 @@ def _create_request # And make sure it worked expect(response.status).to eq(500) expect(ActiveSupport::JSON.decode(response.body)['errors']).to eq([ - "'random_string' is not a valid request state"]) + "'random_string' is not a valid request state" + ]) incoming_messages = IncomingMessage.where(:info_request_id => request_id) @@ -256,7 +257,8 @@ def _create_request expect(response.status).to eq(403) expect(ActiveSupport::JSON.decode(response.body)['errors']).to eq([ - "Request #{request_id} cannot be updated using the API"]) + "Request #{request_id} cannot be updated using the API" + ]) expect(IncomingMessage.count).to eq(n_incoming_messages) expect(OutgoingMessage.count).to eq(n_outgoing_messages) @@ -280,7 +282,8 @@ def _create_request expect(response.status).to eq(403) expect(ActiveSupport::JSON.decode(response.body)['errors']).to eq([ - "You do not own request #{request_id}"]) + "You do not own request #{request_id}" + ]) expect(IncomingMessage.count).to eq(n_incoming_messages) expect(OutgoingMessage.count).to eq(n_outgoing_messages) diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index b4615a5542..2ef49b0623 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -3182,9 +3182,11 @@ def make_request params: { :public_body_ids => [ public_bodies(:humpadink_public_body).id, - public_bodies(:geraldine_public_body).id ], + public_bodies(:geraldine_public_body).id + ], :remove_public_body_ids => [ - public_bodies(:geraldine_public_body).id ] + public_bodies(:geraldine_public_body).id + ] }, session: { :user_id => @user.id } expect(assigns[:public_bodies].size).to eq(1) From 9c4ffee17eded81300335596f62bca837d4fed97 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:08:26 +0100 Subject: [PATCH 007/114] Correct multiline operation indentation Command: `bundle exec rubocop --only Layout/MultilineOperationIndentation --auto-correct` --- app/controllers/admin_general_controller.rb | 4 ++-- app/controllers/admin_user_controller.rb | 2 +- .../info_request_batches_controller.rb | 8 ++++---- .../alaveteli_pro/info_requests_controller.rb | 2 +- app/controllers/application_controller.rb | 6 +++--- app/controllers/password_changes_controller.rb | 6 +++--- app/controllers/request_controller.rb | 16 ++++++++-------- app/models/ability.rb | 8 ++++---- app/models/info_request.rb | 2 +- app/models/info_request_event.rb | 6 +++--- app/models/outgoing_message.rb | 6 +++--- app/models/public_body.rb | 4 ++-- config/preinitializer.rb | 4 ++-- lib/alaveteli_mail_poller.rb | 4 ++-- lib/alaveteli_rate_limiter/rule.rb | 2 +- lib/routing_filters.rb | 2 +- lib/tasks/config_files.rake | 2 +- lib/tasks/temp.rake | 8 ++++---- lib/typeahead_search.rb | 2 +- lib/user_spam_scorer.rb | 2 +- 20 files changed, 48 insertions(+), 48 deletions(-) diff --git a/app/controllers/admin_general_controller.rb b/app/controllers/admin_general_controller.rb index 7215e7b8d7..440217a84d 100644 --- a/app/controllers/admin_general_controller.rb +++ b/app/controllers/admin_general_controller.rb @@ -89,8 +89,8 @@ def index @embargoed_attention_comments ].any?{ |to_do_list| ! to_do_list.empty? } @nothing_to_do = @nothing_to_do && - !@embargoed_request_tasks && - !@embargoed_comment_tasks + !@embargoed_request_tasks && + !@embargoed_comment_tasks end end diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb index 22aa102df9..384198d1fb 100644 --- a/app/controllers/admin_user_controller.rb +++ b/app/controllers/admin_user_controller.rb @@ -152,7 +152,7 @@ def check_role_authorisation def changed_role_ids params[:admin_user][:role_ids].map!{ |role_id| role_id.to_i } (params[:admin_user][:role_ids] - @admin_user.role_ids) | - (@admin_user.role_ids - params[:admin_user][:role_ids]) + (@admin_user.role_ids - params[:admin_user][:role_ids]) end def check_role_requirements diff --git a/app/controllers/alaveteli_pro/info_request_batches_controller.rb b/app/controllers/alaveteli_pro/info_request_batches_controller.rb index 5e26d07e76..a83ed7bdec 100644 --- a/app/controllers/alaveteli_pro/info_request_batches_controller.rb +++ b/app/controllers/alaveteli_pro/info_request_batches_controller.rb @@ -64,7 +64,7 @@ def rate_monitor_limit?(user_id) rate_monitor.limit?(user_id, hour_rule) || rate_monitor.limit?(user_id) || - rate_monitor.limit?(user_id, week_rule) + rate_monitor.limit?(user_id, week_rule) end def handle_rate_monitor_limit_hit(user_id) @@ -104,9 +104,9 @@ def load_data_from_draft(draft) def all_models_valid? @example_info_request.valid? && \ - @outgoing_message.valid? && \ - (@embargo.nil? || @embargo.present? && @embargo.valid?) && \ - @info_request_batch.valid? + @outgoing_message.valid? && \ + (@embargo.nil? || @embargo.present? && @embargo.valid?) && \ + @info_request_batch.valid? end def remove_duplicate_errors diff --git a/app/controllers/alaveteli_pro/info_requests_controller.rb b/app/controllers/alaveteli_pro/info_requests_controller.rb index 5ae4513bb3..0a6c0d081e 100644 --- a/app/controllers/alaveteli_pro/info_requests_controller.rb +++ b/app/controllers/alaveteli_pro/info_requests_controller.rb @@ -77,7 +77,7 @@ def show_errors def all_models_valid? @info_request.valid? && @outgoing_message.valid? && \ - (@embargo.nil? || @embargo.present? && @embargo.valid?) + (@embargo.nil? || @embargo.present? && @embargo.valid?) end def set_draft diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index af8e654c4c..115134b916 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -327,9 +327,9 @@ def authenticated_user def do_post_redirect(post_redirect, user=nil) uri = SafeRedirect.new(post_redirect.uri).path if feature_enabled?(:alaveteli_pro) && - user && - user.is_pro? && - session[:admin_confirmation] != 1 + user && + user.is_pro? && + session[:admin_confirmation] != 1 uri = override_post_redirect_for_pro(uri, post_redirect, user) diff --git a/app/controllers/password_changes_controller.rb b/app/controllers/password_changes_controller.rb index 8cbbd0bbdc..06094ec6b4 100644 --- a/app/controllers/password_changes_controller.rb +++ b/app/controllers/password_changes_controller.rb @@ -79,7 +79,7 @@ def update params[:password_change_user][:password_confirmation] if AlaveteliConfiguration.enable_two_factor_auth && - @password_change_user.otp_enabled? + @password_change_user.otp_enabled? @password_change_user.entered_otp_code = params[:password_change_user][:otp_code] @password_change_user.require_otp = true @@ -90,7 +90,7 @@ def update if @pretoken_redirect if AlaveteliConfiguration.enable_two_factor_auth && - @password_change_user.otp_enabled? + @password_change_user.otp_enabled? msg = _("Your password has been changed. " \ "You also have a new one time passcode which you'll " \ "need next time you want to change your password") @@ -101,7 +101,7 @@ def update end else if AlaveteliConfiguration.enable_two_factor_auth && - @password_change_user.otp_enabled? + @password_change_user.otp_enabled? msg = _("Your password has been changed. " \ "You also have a new one time passcode which you'll " \ "need next time you want to change your password") diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index ebfdb1d85d..fb8294a3d3 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -597,7 +597,7 @@ def authenticate_attachment # Is this a completely public request that we can cache attachments for # to be served up without authentication? if incoming_message.info_request.prominence(:decorate => true).is_public? && - incoming_message.is_public? + incoming_message.is_public? @files_can_be_cached = true end end @@ -618,7 +618,7 @@ def cache_attachments else content_type = AlaveteliFileTypes.filename_to_mimetype(params[:file_name]) || - 'application/octet-stream' + 'application/octet-stream' render :body => foi_fragment_cache_read(key_path), :content_type => content_type @@ -649,7 +649,7 @@ def get_attachment # we don't use @attachment.content_type here, as we want same mime type when cached in cache_attachments above content_type = AlaveteliFileTypes.filename_to_mimetype(params[:file_name]) || - 'application/octet-stream' + 'application/octet-stream' # Prevent spam to magic request address. Note that the binary # subsitution method used depends on the content type @@ -1125,7 +1125,7 @@ def render_new_preview def set_render_recaptcha @render_recaptcha = AlaveteliConfiguration.new_request_recaptcha && - (!@user || !@user.confirmed_not_spam?) + (!@user || !@user.confirmed_not_spam?) end def redirect_numeric_id_to_url_title @@ -1168,9 +1168,9 @@ def redirect_public_requests_from_pro_context def redirect_new_form_to_pro_version # Pros should use the pro version of the form if feature_enabled?(:alaveteli_pro) && - request_user && - request_user.is_pro? && - params[:pro] != "1" + request_user && + request_user.is_pro? && + params[:pro] != "1" if params[:url_name] redirect_to( new_alaveteli_pro_info_request_url(public_body: params[:url_name])) @@ -1218,7 +1218,7 @@ def handle_spam_subject(user) def blocked_ip?(ip, user) !user.confirmed_not_spam? && AlaveteliConfiguration.restricted_countries.include?(ip) && - country_from_ip != AlaveteliConfiguration.iso_country_code + country_from_ip != AlaveteliConfiguration.iso_country_code end def block_restricted_country_ips? diff --git a/app/models/ability.rb b/app/models/ability.rb index 3363bb7258..bafa61a627 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -85,10 +85,10 @@ def initialize(user) # Creating embargoes can :create_embargo, InfoRequest do |info_request| user && info_request.user && - info_request.user.is_pro? && - (user.is_pro_admin? || user == info_request.user) && - !info_request.embargo && - info_request.info_request_batch_id.nil? + info_request.user.is_pro? && + (user.is_pro_admin? || user == info_request.user) && + !info_request.embargo && + info_request.info_request_batch_id.nil? end # Extending embargoes diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 1d5fdd5ef2..cc155bd517 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -1875,7 +1875,7 @@ def applicable_law def title_formatting return unless title unless MySociety::Validate.uses_mixed_capitals(title, 1) || - title_starts_with_number || title_is_acronym(6) + title_starts_with_number || title_is_acronym(6) errors.add(:title, _('Please write the summary using a mixture of capital and lower case letters. This makes it easier for others to read.')) end if title =~ /^(FOI|Freedom of Information)\s*requests?$/i diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index c93b7dd3a4..27254b1ceb 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -450,9 +450,9 @@ def response? def only_editing_prominence_to_hide? event_type == 'edit' && - params_diff[:new].keys == [:prominence] && - params_diff[:old][:prominence] == "normal" && - %w(hidden requester_only backpage).include?(params_diff[:new][:prominence]) + params_diff[:new].keys == [:prominence] && + params_diff[:old][:prominence] == "normal" && + %w(hidden requester_only backpage).include?(params_diff[:new][:prominence]) end # This method updates the cached column of the InfoRequest that diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index b2c77e26a4..a6fee0aeed 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -402,13 +402,13 @@ def default_message_replacements def replying_to_incoming_message? message_type == 'followup' && incoming_message_followup && - incoming_message_followup.safe_mail_from && - incoming_message_followup.valid_to_reply_to? + incoming_message_followup.safe_mail_from && + incoming_message_followup.valid_to_reply_to? end def template_changed if raw_body.empty? || HTMLEntities.new.decode(raw_body) =~ - /\A#{template_regex(letter_template.body(default_message_replacements))}/ + /\A#{template_regex(letter_template.body(default_message_replacements))}/ if message_type == 'followup' if what_doing == 'internal_review' errors.add(:body, _("Please give details explaining why you want a review")) diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 32b647604b..b555434d5e 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -166,7 +166,7 @@ class Version def copy_translated_attributes public_body.attributes.each do |name, value| if public_body.translated?(name) && - !public_body.non_versioned_columns.include?(name) + !public_body.non_versioned_columns.include?(name) send("#{name}=", value) end end @@ -610,7 +610,7 @@ def is_foi_officer?(user) def request_email if AlaveteliConfiguration.override_all_public_body_request_emails.blank? || - read_attribute(:request_email).blank? + read_attribute(:request_email).blank? read_attribute(:request_email) else AlaveteliConfiguration.override_all_public_body_request_emails diff --git a/config/preinitializer.rb b/config/preinitializer.rb index 71112a28e5..db38fcd3d1 100644 --- a/config/preinitializer.rb +++ b/config/preinitializer.rb @@ -8,7 +8,7 @@ if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24") raise RuntimeError, "Your bundler version is too old for Rails 2.3." + - "Run `gem install bundler` to upgrade." + "Run `gem install bundler` to upgrade." end begin @@ -17,5 +17,5 @@ Bundler.setup rescue Bundler::GemNotFound raise RuntimeError, "Bundler couldn't find some gems." + - "Did you run `bundle install`?" + "Did you run `bundle install`?" end diff --git a/lib/alaveteli_mail_poller.rb b/lib/alaveteli_mail_poller.rb index 09fdb4011f..853bcb5864 100644 --- a/lib/alaveteli_mail_poller.rb +++ b/lib/alaveteli_mail_poller.rb @@ -95,8 +95,8 @@ def retry?(unique_id) incoming_message_error = IncomingMessageError. where(unique_id: unique_id).take incoming_message_error && - incoming_message_error.retry_at && - incoming_message_error.retry_at < Time.zone.now + incoming_message_error.retry_at && + incoming_message_error.retry_at < Time.zone.now end def retrieve?(unique_id) diff --git a/lib/alaveteli_rate_limiter/rule.rb b/lib/alaveteli_rate_limiter/rule.rb index 3d7f5e00f2..5e439ae31b 100644 --- a/lib/alaveteli_rate_limiter/rule.rb +++ b/lib/alaveteli_rate_limiter/rule.rb @@ -38,7 +38,7 @@ def initialize(name, count, window) def ==(other) name == other.name && count == other.count && - window == other.window + window == other.window end # Public: Are there more records in the Window than the Rule allows? diff --git a/lib/routing_filters.rb b/lib/routing_filters.rb index cd57493cb5..febf478ad5 100644 --- a/lib/routing_filters.rb +++ b/lib/routing_filters.rb @@ -12,7 +12,7 @@ class Conditionallyprependlocale < RoutingFilter::Locale def prepend_locale?(locale) locale && AlaveteliLocalization.available_locales.length > 1 && - (self.class.include_default_locale? || !default_locale?(locale)) + (self.class.include_default_locale? || !default_locale?(locale)) end # And override the generation logic to use FastGettext.locale # rather than I18n.locale (the latter is what rails uses diff --git a/lib/tasks/config_files.rake b/lib/tasks/config_files.rake index 57e4139c8e..445d82dcc6 100644 --- a/lib/tasks/config_files.rake +++ b/lib/tasks/config_files.rake @@ -25,7 +25,7 @@ namespace :config_files do def daemons(only_active = false) daemons = [ 'alert-tracks', 'send-notifications' ] if AlaveteliConfiguration.production_mailer_retriever_method == 'pop' || - !only_active + !only_active daemons << 'poll-for-incoming' end daemons diff --git a/lib/tasks/temp.rake b/lib/tasks/temp.rake index 783d1a0a90..e31e9c207f 100644 --- a/lib/tasks/temp.rake +++ b/lib/tasks/temp.rake @@ -350,10 +350,10 @@ namespace :temp do IncomingMessage.find_each do |incoming_message| if (incoming_message.cached_attachment_text_clipped && !incoming_message.cached_attachment_text_clipped.valid_encoding?) || - (incoming_message.cached_main_body_text_folded && - !incoming_message.cached_main_body_text_folded.valid_encoding?) || - (incoming_message.cached_main_body_text_unfolded && - !incoming_message.cached_main_body_text_unfolded.valid_encoding?) + (incoming_message.cached_main_body_text_folded && + !incoming_message.cached_main_body_text_folded.valid_encoding?) || + (incoming_message.cached_main_body_text_unfolded && + !incoming_message.cached_main_body_text_unfolded.valid_encoding?) puts "Bad encoding in IncomingMessage cached fields, :id #{incoming_message.id} " unless dryrun incoming_message.clear_in_database_caches! diff --git a/lib/typeahead_search.rb b/lib/typeahead_search.rb index 57eaeefef7..1d4f014c9a 100644 --- a/lib/typeahead_search.rb +++ b/lib/typeahead_search.rb @@ -78,7 +78,7 @@ def flags def default_flags Xapian::QueryParser::FLAG_LOVEHATE | - Xapian::QueryParser::FLAG_SPELLING_CORRECTION + Xapian::QueryParser::FLAG_SPELLING_CORRECTION end def prepared_query diff --git a/lib/user_spam_scorer.rb b/lib/user_spam_scorer.rb index 1e528d68ef..83c747823d 100644 --- a/lib/user_spam_scorer.rb +++ b/lib/user_spam_scorer.rb @@ -106,7 +106,7 @@ class UserSpamScorer define_singleton_method key do value = instance_variable_get("@#{ key }") || - const_get("DEFAULT_#{ key }".upcase) + const_get("DEFAULT_#{ key }".upcase) instance_variable_set("@#{ key }", value) end end From 9b022ec1aaed3c9d34a84c2ff7a1d9eb27bb2e47 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:12:55 +0100 Subject: [PATCH 008/114] Correct space before block braces Command: `bundle exec rubocop --only Layout/SpaceBeforeBlockBraces --auto-correct` --- app/controllers/admin_general_controller.rb | 10 +-- app/controllers/admin_user_controller.rb | 6 +- app/controllers/application_controller.rb | 6 +- app/controllers/request_controller.rb | 2 +- app/controllers/track_controller.rb | 2 +- app/controllers/user_controller.rb | 2 +- app/helpers/application_helper.rb | 2 +- .../alaveteli_pro/activity_list/list.rb | 2 +- app/models/alaveteli_pro/request_filter.rb | 10 +-- app/models/alaveteli_pro/to_do_list/list.rb | 4 +- app/models/foi_attachment.rb | 2 +- app/models/holiday_import.rb | 4 +- app/models/incoming_message.rb | 6 +- app/models/info_request.rb | 10 +-- app/models/info_request/state.rb | 2 +- app/models/public_body.rb | 4 +- app/models/public_body_change_request.rb | 10 +-- app/models/user.rb | 2 +- lib/acts_as_xapian/acts_as_xapian.rb | 14 ++-- lib/acts_as_xapian/tasks/xapian.rake | 4 +- lib/i18n_fixes.rb | 2 +- lib/mail_handler/backends/mail_backend.rb | 2 +- lib/mail_handler/mail_handler.rb | 2 +- lib/tasks/stats.rake | 2 +- lib/tasks/temp.rake | 4 +- lib/typeahead_search.rb | 2 +- lib/use_spans_for_errors.rb | 2 +- lib/world_foi_websites.rb | 2 +- .../admin_comment_controller_spec.rb | 18 ++--- .../admin_general_controller_spec.rb | 4 +- ..._public_body_categories_controller_spec.rb | 8 +- .../admin_public_body_controller_spec.rb | 12 +-- ...in_public_body_headings_controller_spec.rb | 8 +- .../admin_request_controller_spec.rb | 26 +++---- .../admin_track_controller_spec.rb | 2 +- .../controllers/admin_user_controller_spec.rb | 8 +- .../account_request_controller_spec.rb | 2 +- spec/controllers/general_controller_spec.rb | 14 ++-- spec/controllers/help_controller_spec.rb | 6 +- .../public_body_controller_spec.rb | 10 +-- spec/controllers/reports_controller_spec.rb | 8 +- spec/controllers/request_controller_spec.rb | 50 ++++++------- spec/controllers/user_controller_spec.rb | 8 +- .../users/sessions_controller_spec.rb | 2 +- .../widget_votes_controller_spec.rb | 2 +- spec/helpers/application_helper_spec.rb | 2 +- spec/helpers/info_request_helper_spec.rb | 10 +-- spec/integration/alaveteli_dsl.rb | 2 +- .../alaveteli_pro/request_list_spec.rb | 2 +- spec/integration/download_request_spec.rb | 2 +- spec/integration/incoming_mail_spec.rb | 2 +- spec/integration/signin_spec.rb | 2 +- spec/integration/view_request_spec.rb | 2 +- spec/lib/alaveteli_text_masker_spec.rb | 6 +- .../health_checks/health_checkable_spec.rb | 2 +- spec/lib/mail_handler/mail_handler_spec.rb | 4 +- spec/lib/typeahead_search_spec.rb | 6 +- spec/lib/user_spam_scorer_spec.rb | 2 +- .../alaveteli_pro/embargo_mailer_spec.rb | 14 ++-- spec/mailers/application_mailer_spec.rb | 6 +- spec/mailers/request_mailer_spec.rb | 4 +- spec/mailers/track_mailer_spec.rb | 2 +- spec/models/ability_spec.rb | 12 +-- .../activity_list/comment_spec.rb | 8 +- .../activity_list/embargo_expiry_spec.rb | 8 +- .../activity_list/followup_resent_spec.rb | 4 +- .../activity_list/followup_sent_spec.rb | 4 +- .../alaveteli_pro/activity_list/item_spec.rb | 2 +- .../alaveteli_pro/activity_list/list_spec.rb | 4 +- .../activity_list/new_response_spec.rb | 4 +- .../activity_list/overdue_spec.rb | 4 +- .../activity_list/request_resent_spec.rb | 4 +- .../activity_list/request_sent_spec.rb | 4 +- .../activity_list/very_overdue_spec.rb | 4 +- .../alaveteli_pro/request_filter_spec.rb | 2 +- .../alaveteli_pro/to_do_list/item_spec.rb | 2 +- .../alaveteli_pro/to_do_list/list_spec.rb | 2 +- .../to_do_list/very_overdue_request_spec.rb | 2 +- spec/models/incoming_message_spec.rb | 4 +- .../prominence/calculator_spec.rb | 4 +- .../authority_only_spec.rb | 2 +- .../response_gatekeeper/base_spec.rb | 4 +- .../response_gatekeeper/nobody_spec.rb | 2 +- .../info_request/response_gatekeeper_spec.rb | 2 +- .../response_rejection/base_spec.rb | 6 +- .../info_request/response_rejection_spec.rb | 2 +- .../state/clarification_needed_query_spec.rb | 2 +- .../info_request/state/complete_query_spec.rb | 2 +- .../info_request/state/other_query_spec.rb | 2 +- .../info_request/state/overdue_query_spec.rb | 4 +- .../state/response_received_query_spec.rb | 2 +- .../state/very_overdue_query_spec.rb | 4 +- spec/models/info_request/state_spec.rb | 4 +- spec/models/info_request_spec.rb | 74 +++++++++---------- spec/models/outgoing_message_spec.rb | 2 +- spec/models/pro_account_spec.rb | 2 +- spec/models/public_body_spec.rb | 8 +- spec/models/raw_email_spec.rb | 2 +- spec/models/user_spec.rb | 18 ++--- spec/models/xapian_spec.rb | 6 +- spec/support/email_helpers.rb | 4 +- .../admin_public_body/show.html.erb_spec.rb | 6 +- .../views/admin_request/show.html.erb_spec.rb | 4 +- spec/views/admin_user/show.html.erb_spec.rb | 8 +- 104 files changed, 315 insertions(+), 315 deletions(-) diff --git a/app/controllers/admin_general_controller.rb b/app/controllers/admin_general_controller.rb index 440217a84d..86d4dea4ee 100644 --- a/app/controllers/admin_general_controller.rb +++ b/app/controllers/admin_general_controller.rb @@ -30,7 +30,7 @@ def index @attention_requests, @requires_admin_requests, @old_unclassified ]. - any?{ |to_do_list| ! to_do_list.empty? } + any? { |to_do_list| ! to_do_list.empty? } @blank_contact_count = PublicBody.without_request_email.count @blank_contacts = PublicBody.without_request_email.limit(20) @@ -47,14 +47,14 @@ def index @authority_tasks = [ @blank_contacts, @new_body_requests, @body_update_requests ]. - any?{ |to_do_list| ! to_do_list.empty? } + any? { |to_do_list| ! to_do_list.empty? } # HACK: Running this query through ActiveRecord freezes… @attention_comments = Comment. find_by_sql(Comment.where(attention_requested: true).not_embargoed.to_sql) @comment_tasks = [ @attention_comments ]. - any?{ |to_do_list| ! to_do_list.empty? } + any? { |to_do_list| ! to_do_list.empty? } @nothing_to_do = !@public_request_tasks && !@authority_tasks && @@ -79,7 +79,7 @@ def index @embargoed_requires_admin_requests, @embargoed_error_message_requests, @embargoed_attention_requests, - ].any?{ |to_do_list| ! to_do_list.empty? } + ].any? { |to_do_list| ! to_do_list.empty? } @embargoed_attention_comments = Comment. where(:attention_requested => true). @@ -87,7 +87,7 @@ def index @embargoed_comment_tasks = [ @embargoed_attention_comments - ].any?{ |to_do_list| ! to_do_list.empty? } + ].any? { |to_do_list| ! to_do_list.empty? } @nothing_to_do = @nothing_to_do && !@embargoed_request_tasks && !@embargoed_comment_tasks diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb index 384198d1fb..903a5da229 100644 --- a/app/controllers/admin_user_controller.rb +++ b/app/controllers/admin_user_controller.rb @@ -38,7 +38,7 @@ def index # so we need to requery in order to paginate if !@roles.empty? users = users.with_any_role(*@roles) - users = User.where(:id => users.map{ |user| user.id }) + users = User.where(:id => users.map { |user| user.id }) end @admin_users = @@ -150,7 +150,7 @@ def check_role_authorisation end def changed_role_ids - params[:admin_user][:role_ids].map!{ |role_id| role_id.to_i } + params[:admin_user][:role_ids].map! { |role_id| role_id.to_i } (params[:admin_user][:role_ids] - @admin_user.role_ids) | (@admin_user.role_ids - params[:admin_user][:role_ids]) end @@ -158,7 +158,7 @@ def changed_role_ids def check_role_requirements role_names = Role. where(:id => params[:admin_user][:role_ids]). - pluck(:name).map{ |role| role.to_sym } + pluck(:name).map { |role| role.to_sym } missing_required = Hash.new { |h, k| h[k] = [] } role_names.each do |role_name| Role.requires(role_name).each do |required_role_name| diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 115134b916..f918a3dc6d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -189,8 +189,8 @@ def render_exception(exception) @status = 500 end respond_to do |format| - format.html{ render :template => "general/exception_caught", :status => @status } - format.any{ head @status } + format.html { render :template => "general/exception_caught", :status => @status } + format.any { head @status } end end @@ -223,7 +223,7 @@ def foi_fragment_cache_path(param) max_file_length = 255 - 35 # we subtract 35 because tempfile # adds on a variable number of # characters - return File.join(File.split(path).map{|x| x[0...max_file_length]}) + return File.join(File.split(path).map {|x| x[0...max_file_length]}) end def foi_fragment_cache_exists?(key_path) diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index fb8294a3d3..ebf0dd979e 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -68,7 +68,7 @@ def select_authorities end format.json do if @search_bodies - render :json => @search_bodies.results.map{ |result| {:name => result[:model].name, + render :json => @search_bodies.results.map { |result| {:name => result[:model].name, :id => result[:model].id } } else render :json => [] diff --git a/app/controllers/track_controller.rb b/app/controllers/track_controller.rb index 58e69405ae..9ba94db18e 100644 --- a/app/controllers/track_controller.rb +++ b/app/controllers/track_controller.rb @@ -148,7 +148,7 @@ def track_set return true else # this will most likely be tripped by a single error - probably track_query length - flash[:error] = @track_thing.errors.map{ |_, msg| msg }.join(", ") + flash[:error] = @track_thing.errors.map { |_, msg| msg }.join(", ") return false end end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index b5a3519cd6..68f28355ab 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -136,7 +136,7 @@ def signup if user_alreadyexists # attempt to remove the 'already in use message' from the errors hash # so it doesn't get accidentally shown to the end user - @user_signup.errors[:email].delete_if{|message| message == _("This email is already in use")} + @user_signup.errors[:email].delete_if {|message| message == _("This email is already in use")} end if error || !@user_signup.errors.empty? # Show the form diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0d1d5703e4..fd8c66b4d6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -146,7 +146,7 @@ def render_flash(flash) # views def request_list_cache_key cacheable_param_list = ['controller', 'action', 'locale', 'view'] - if params.keys.all?{ |key| cacheable_param_list.include?(key) } + if params.keys.all? { |key| cacheable_param_list.include?(key) } "request-list-#{@view}-#{@locale}" else nil diff --git a/app/models/alaveteli_pro/activity_list/list.rb b/app/models/alaveteli_pro/activity_list/list.rb index fafdc59d64..0997815a92 100644 --- a/app/models/alaveteli_pro/activity_list/list.rb +++ b/app/models/alaveteli_pro/activity_list/list.rb @@ -22,7 +22,7 @@ def events def current_items current_events = events.paginate :page => page, :per_page => per_page - current_events.map{ |event| activity_types[event.event_type].new(event) } + current_events.map { |event| activity_types[event.event_type].new(event) } end private diff --git a/app/models/alaveteli_pro/request_filter.rb b/app/models/alaveteli_pro/request_filter.rb index b1fec8c2f3..a55846af8b 100644 --- a/app/models/alaveteli_pro/request_filter.rb +++ b/app/models/alaveteli_pro/request_filter.rb @@ -83,11 +83,11 @@ def order_attributes end def order_params - order_attributes.map{ |atts| atts[:param] } + order_attributes.map { |atts| atts[:param] } end def order_values - Hash[order_attributes.map{ |atts| [ atts[:param], atts[:value] ] }] + Hash[order_attributes.map { |atts| [ atts[:param], atts[:value] ] }] end def order_capital_labels @@ -121,7 +121,7 @@ def default_filters end def phase_filters - InfoRequest::State.phases.map{ |phase| { :param => phase[:scope].to_s, + InfoRequest::State.phases.map { |phase| { :param => phase[:scope].to_s, :value => phase[:scope], :label => phase[:label], :capital_label => phase[:capital_label] } } @@ -140,11 +140,11 @@ def filter_capital_labels end def filter_params - filter_attributes.map{ |atts| atts[:param] } + filter_attributes.map { |atts| atts[:param] } end def filter_values - Hash[ filter_attributes.map{ |atts| [ atts[:param], atts[:value] ] } ] + Hash[ filter_attributes.map { |atts| [ atts[:param], atts[:value] ] } ] end def filter_labels diff --git a/app/models/alaveteli_pro/to_do_list/list.rb b/app/models/alaveteli_pro/to_do_list/list.rb index 88771a1466..eaad21d031 100644 --- a/app/models/alaveteli_pro/to_do_list/list.rb +++ b/app/models/alaveteli_pro/to_do_list/list.rb @@ -10,11 +10,11 @@ def initialize(user) end def items - self.class.item_types.map{ |item_type| item_type.new(user) } + self.class.item_types.map { |item_type| item_type.new(user) } end def active_items - items.select{ |item| item.count > 0 } + items.select { |item| item.count > 0 } end private diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index 4c26fc5525..5324d4bddb 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -77,7 +77,7 @@ def body tries = 0 delay = 1 begin - @cached_body = File.open(filepath, "rb" ){ |file| file.read } + @cached_body = File.open(filepath, "rb" ) { |file| file.read } rescue Errno::ENOENT # we've lost our cached attachments for some reason. Reparse them. if tries > BODY_MAX_TRIES diff --git a/app/models/holiday_import.rb b/app/models/holiday_import.rb index 3f1eee530e..b963e26aa1 100644 --- a/app/models/holiday_import.rb +++ b/app/models/holiday_import.rb @@ -47,7 +47,7 @@ def save end def holidays_attributes=(incoming_data) - incoming_data.each{ |offset, incoming| self.holidays << Holiday.new(incoming) } + incoming_data.each { |offset, incoming| self.holidays << Holiday.new(incoming) } end def holidays @@ -70,7 +70,7 @@ def populate_from_ical_feed errors.add(:ical_feed_url, "Sorry, there's a problem with the format of that feed.") return end - cal.events.each{ |cal_event| populate_from_ical_event(cal_event) } + cal.events.each { |cal_event| populate_from_ical_event(cal_event) } rescue Errno::ENOENT, Exception => e if e.message == 'Invalid line in calendar string!' errors.add(:ical_feed_url, "Sorry, there's a problem with the format of that feed.") diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index 30b019ee59..ab2c6beeda 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -83,7 +83,7 @@ class IncomingMessage < ApplicationRecord # Given that there are in theory many info request events, a convenience method for # getting the response event def response_event - self.info_request_events.detect{ |e| e.event_type == 'response' } + self.info_request_events.detect { |e| e.event_type == 'response' } end def parse_raw_email!(force = nil) @@ -565,7 +565,7 @@ def extract_attachments! end end - attachment_ids = attachments.map{ |attachment| attachment.id } + attachment_ids = attachments.map { |attachment| attachment.id } # now get rid of any attachments we no longer have FoiAttachment. where( @@ -662,7 +662,7 @@ def get_attachment_text_clipped def _extract_text # Extract text from each attachment - self.get_attachments_for_display.reduce(''){ |memo, attachment| + self.get_attachments_for_display.reduce('') { |memo, attachment| memo += MailHandler.get_attachment_text_one_file(attachment.content_type, attachment.default_body, attachment.charset) diff --git a/app/models/info_request.rb b/app/models/info_request.rb index cc155bd517..21d42cb981 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -614,7 +614,7 @@ def self.recent_requests more_events = xapian_object.results.map { |r| r[:model] } request_events += more_events # Overall we still want the list sorted with the newest first - request_events.sort!{|e1,e2| e2.created_at <=> e1.created_at} + request_events.sort! {|e1,e2| e2.created_at <=> e1.created_at} else request_events_all_successful = true end @@ -790,7 +790,7 @@ def tag_string=(tag_string) def expire(options={}) # Clear out cached entries, by removing files from disk (the built in # Rails fragment cache made doing this and other things too hard) - foi_fragment_cache_directories.each{ |dir| FileUtils.rm_rf(dir) } + foi_fragment_cache_directories.each { |dir| FileUtils.rm_rf(dir) } # Remove any download zips FileUtils.rm_rf(download_zip_dir) @@ -1265,7 +1265,7 @@ def get_last_public_response end def public_outgoing_events - info_request_events.select{|e| e.outgoing? && e.outgoing_message.is_public? } + info_request_events.select {|e| e.outgoing? && e.outgoing_message.is_public? } end # The last public outgoing message @@ -1516,8 +1516,8 @@ def is_actual_owning_user?(user) def all_correspondence_is_public? prominence(:decorate => true).is_public? && - incoming_messages.all?{ |message| message.is_public? } && - outgoing_messages.all?{ |message| message.is_public? } + incoming_messages.all? { |message| message.is_public? } && + outgoing_messages.all? { |message| message.is_public? } end def json_for_api(deep) diff --git a/app/models/info_request/state.rb b/app/models/info_request/state.rb index 8c630ee5c1..3b597f6495 100644 --- a/app/models/info_request/state.rb +++ b/app/models/info_request/state.rb @@ -92,7 +92,7 @@ def self.phases end def self.phase_params - Hash[phases.map{ |atts| [ atts[:scope], atts[:param] ]}] + Hash[phases.map { |atts| [ atts[:scope], atts[:param] ]}] end end end diff --git a/app/models/public_body.rb b/app/models/public_body.rb index b555434d5e..62e8e45fcd 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -482,7 +482,7 @@ def self.import_csv_from_file(csv_filename, tag, tag_behaviour, dry_run, editor, end fields = {} - field_names.each{ |name, i| fields[name] = row[i] } + field_names.each { |name, i| fields[name] = row[i] } yield line, fields if block_given? @@ -577,7 +577,7 @@ def set_locale_fields_from_csv_row(is_new, locale, row, options) # Tags are a special case, as we support adding to the field, # not just setting a new value if field_name == 'tag_string' - new_tags = [value, options[:tag]].select{ |new_tag| !new_tag.blank? } + new_tags = [value, options[:tag]].select { |new_tag| !new_tag.blank? } if new_tags.empty? value = nil else diff --git a/app/models/public_body_change_request.rb b/app/models/public_body_change_request.rb index fa7f70098d..eb74594d04 100644 --- a/app/models/public_body_change_request.rb +++ b/app/models/public_body_change_request.rb @@ -26,15 +26,15 @@ class PublicBodyChangeRequest < ApplicationRecord validates_presence_of :public_body_name, :message => N_("Please enter the name of the authority"), - :unless => proc{ |change_request| change_request.public_body } + :unless => proc { |change_request| change_request.public_body } validates_presence_of :user_name, :message => N_("Please enter your name"), - :unless => proc{ |change_request| change_request.user } + :unless => proc { |change_request| change_request.user } validates_presence_of :user_email, :message => N_("Please enter your email address"), - :unless => proc{ |change_request| change_request.user } - validate :user_email_format, :unless => proc{ |change_request| change_request.user_email.blank? } - validate :body_email_format, :unless => proc{ |change_request| change_request.public_body_email.blank? } + :unless => proc { |change_request| change_request.user } + validate :user_email_format, :unless => proc { |change_request| change_request.user_email.blank? } + validate :body_email_format, :unless => proc { |change_request| change_request.public_body_email.blank? } scope :new_body_requests, -> { where(public_body_id: nil).order("created_at") diff --git a/app/models/user.rb b/app/models/user.rb index a1b13c3e92..d561966625 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -433,7 +433,7 @@ def owns_every_request? end def can_admin_roles - roles.flat_map{ |role| Role.grants_and_revokes(role.name.to_sym) }.compact.uniq + roles.flat_map { |role| Role.grants_and_revokes(role.name.to_sym) }.compact.uniq end def can_admin_role?(role) diff --git a/lib/acts_as_xapian/acts_as_xapian.rb b/lib/acts_as_xapian/acts_as_xapian.rb index d0e7ca408c..e66205add2 100644 --- a/lib/acts_as_xapian/acts_as_xapian.rb +++ b/lib/acts_as_xapian/acts_as_xapian.rb @@ -478,7 +478,7 @@ def initialize(model_classes, query_string, options = {}, user_query = nil) self.query_string = query_string # Construct query which only finds things from specified models - model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s}) + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map {|mc| "M" + mc.to_s}) if user_query.nil? user_query = ActsAsXapian.query_parser.parse_query( self.query_string, @@ -559,7 +559,7 @@ def initialize(model_classes, query_models, options = {}) self.query_models = query_models # Find the documents by their unique term - input_models_query = Xapian::Query.new(Xapian::Query::OP_OR, query_models.map{|m| "I" + m.xapian_document_term}) + input_models_query = Xapian::Query.new(Xapian::Query::OP_OR, query_models.map {|m| "I" + m.xapian_document_term}) ActsAsXapian.enquire.query = input_models_query matches = ActsAsXapian.enquire.mset(0, 100, 100) # TODO: so this whole method will only work with 100 docs @@ -589,7 +589,7 @@ def initialize(model_classes, query_models, options = {}) combined_query = Xapian::Query.new(Xapian::Query::OP_AND_NOT, similar_query, input_models_query) # Restrain to model classes - model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s}) + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map {|mc| "M" + mc.to_s}) self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, combined_query) } @@ -901,16 +901,16 @@ def xapian_value(field, type = nil, index_translations = false) value = single_xapian_value(field, type = type) else values = [] - for locale in self.translations.map{|x| x.locale} + for locale in self.translations.map {|x| x.locale} AlaveteliLocalization.with_locale(locale) do values << single_xapian_value(field, type=type) end end if values[0].kind_of?(Array) values = values.flatten - value = values.reject{|x| x.nil?} + value = values.reject {|x| x.nil?} else - values = values.reject{|x| x.nil?} + values = values.reject {|x| x.nil?} value = values.join(" ") end end @@ -973,7 +973,7 @@ def xapian_index(terms = true, values = true, texts = true) if terms and self.xapian_options[:terms] terms_to_index = self.xapian_options[:terms].dup if terms.is_a?(String) - terms_to_index.reject!{|term| !terms.include?(term[1])} + terms_to_index.reject! {|term| !terms.include?(term[1])} if terms_to_index.length == self.xapian_options[:terms].length drop_all_terms = true end diff --git a/lib/acts_as_xapian/tasks/xapian.rake b/lib/acts_as_xapian/tasks/xapian.rake index 9e0067ce3d..a01df6b8d0 100644 --- a/lib/acts_as_xapian/tasks/xapian.rake +++ b/lib/acts_as_xapian/tasks/xapian.rake @@ -41,7 +41,7 @@ namespace :xapian do end raise "specify ALL your models with models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? ActsAsXapian.destroy_and_rebuild_index( - ENV['models'].split(" ").map{|m| m.constantize}, + ENV['models'].split(" ").map {|m| m.constantize}, coerce_arg(ENV['verbose'], false), coerce_arg(ENV['terms'], true), coerce_arg(ENV['values'], true), @@ -54,7 +54,7 @@ namespace :xapian do task :query => :environment do raise "specify models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? raise "specify query=\"your terms\" as parameter" if ENV['query'].nil? - s = ActsAsXapian::Search.new(ENV['models'].split(" ").map{|m| m.constantize}, + s = ActsAsXapian::Search.new(ENV['models'].split(" ").map {|m| m.constantize}, ENV['query'], :offset => (ENV['offset'] || 0), :limit => (ENV['limit'] || 10), :sort_by_prefix => (ENV['sort_by_prefix'] || nil), diff --git a/lib/i18n_fixes.rb b/lib/i18n_fixes.rb index 97ffa5021a..6e70f44fdf 100644 --- a/lib/i18n_fixes.rb +++ b/lib/i18n_fixes.rb @@ -52,7 +52,7 @@ def gettext_interpolate(string, values) module GettextI18nRails class Backend def available_locales - FastGettext.available_locales.map{|l| l.to_sym} || [] + FastGettext.available_locales.map {|l| l.to_sym} || [] end end end diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 0456a395e6..fd90a77d6b 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -213,7 +213,7 @@ def decode_attached_part(part, parent_mail) # set. Tries to set a more specific content type for binary content types. def expand_and_normalize_parts(part, parent_mail) if part.multipart? - Mail::PartsList.new(part.parts.each{ |sub_part| expand_and_normalize_parts(sub_part, parent_mail) }) + Mail::PartsList.new(part.parts.each { |sub_part| expand_and_normalize_parts(sub_part, parent_mail) }) else part_filename = get_part_file_name(part) if part.has_charset? diff --git a/lib/mail_handler/mail_handler.rb b/lib/mail_handler/mail_handler.rb index 88a005fa20..5fc576b849 100644 --- a/lib/mail_handler/mail_handler.rb +++ b/lib/mail_handler/mail_handler.rb @@ -127,7 +127,7 @@ def get_attachment_text_one_file(content_type, body, charset = 'utf-8') {:binary_output => false}) if !xml.nil? doc = REXML::Document.new(xml) - text += doc.each_element( './/text()' ){}.join(" ") + text += doc.each_element( './/text()' ) {}.join(" ") end elsif content_type == 'application/zip' # recurse into zip files diff --git a/lib/tasks/stats.rake b/lib/tasks/stats.rake index a568c8e88b..ba4a08ff8b 100644 --- a/lib/tasks/stats.rake +++ b/lib/tasks/stats.rake @@ -134,7 +134,7 @@ namespace :stats do puts "Bodies with tag '#{tag}': #{tag_bodies.size}" public_bodies += tag_bodies end - public_body_ids = public_bodies.map{ |body| body.id }.uniq + public_body_ids = public_bodies.map { |body| body.id }.uniq public_body_condition_string = 'AND public_bodies.id in (?)' month_starts = (Date.new(start_year, start_month)..Date.new(end_year, end_month)).select { |d| d.day == 1 } headers = ['Period', diff --git a/lib/tasks/temp.rake b/lib/tasks/temp.rake index e31e9c207f..d5096445c8 100644 --- a/lib/tasks/temp.rake +++ b/lib/tasks/temp.rake @@ -169,8 +169,8 @@ namespace :temp do puts [ info_request.id, info_request.url_title, - info_request.applicable_censor_rules.map{ |rule| rule.id }.join(","), - info_request.applicable_censor_rules.map{ |rule| rule.text }.join(","), + info_request.applicable_censor_rules.map { |rule| rule.id }.join(","), + info_request.applicable_censor_rules.map { |rule| rule.text }.join(","), cached_types.uniq.join(",") ].join("\t") end diff --git a/lib/typeahead_search.rb b/lib/typeahead_search.rb index 1d4f014c9a..6434a3098d 100644 --- a/lib/typeahead_search.rb +++ b/lib/typeahead_search.rb @@ -90,7 +90,7 @@ def prepared_query @query end if @exclude_tags - tag_string = @exclude_tags.map{|tag| "-tag:#{tag}"}.join(" ") + tag_string = @exclude_tags.map {|tag| "-tag:#{tag}"}.join(" ") query = "#{query} #{tag_string}" end query diff --git a/lib/use_spans_for_errors.rb b/lib/use_spans_for_errors.rb index 053258adf0..5da8aec98f 100644 --- a/lib/use_spans_for_errors.rb +++ b/lib/use_spans_for_errors.rb @@ -9,4 +9,4 @@ # # See http://dev.rubyonrails.org/ticket/2210 -ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| %(#{html_tag}).html_safe} +ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| %(#{html_tag}).html_safe} diff --git a/lib/world_foi_websites.rb b/lib/world_foi_websites.rb index 45029520cc..28f2b6a9d8 100644 --- a/lib/world_foi_websites.rb +++ b/lib/world_foi_websites.rb @@ -140,7 +140,7 @@ def self.world_foi_websites end def self.by_code(code) - result = self.world_foi_websites.find{|x| x[:country_iso_code].downcase == code.downcase} + result = self.world_foi_websites.find {|x| x[:country_iso_code].downcase == code.downcase} return result end diff --git a/spec/controllers/admin_comment_controller_spec.rb b/spec/controllers/admin_comment_controller_spec.rb index 6e851d7b37..ca2a5d38c6 100644 --- a/spec/controllers/admin_comment_controller_spec.rb +++ b/spec/controllers/admin_comment_controller_spec.rb @@ -4,8 +4,8 @@ describe AdminCommentController do describe 'GET index' do - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } it 'sets the title' do get :index, session: { :user_id => admin_user.id } @@ -82,9 +82,9 @@ end describe 'GET edit' do - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:comment){ FactoryBot.create(:comment) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:comment) { FactoryBot.create(:comment) } it 'renders the edit template' do get :edit, params: { :id => comment.id }, @@ -129,10 +129,10 @@ end describe 'PUT update' do - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:comment){ FactoryBot.create(:comment) } - let(:atts){ FactoryBot.attributes_for(:comment, :body => 'I am new') } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:comment) { FactoryBot.create(:comment) } + let(:atts) { FactoryBot.attributes_for(:comment, :body => 'I am new') } context 'on valid data submission' do diff --git a/spec/controllers/admin_general_controller_spec.rb b/spec/controllers/admin_general_controller_spec.rb index 53a2a6498d..2a8dd38c33 100644 --- a/spec/controllers/admin_general_controller_spec.rb +++ b/spec/controllers/admin_general_controller_spec.rb @@ -4,8 +4,8 @@ describe AdminGeneralController do describe "GET #index" do - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } before do InfoRequest.destroy_all diff --git a/spec/controllers/admin_public_body_categories_controller_spec.rb b/spec/controllers/admin_public_body_categories_controller_spec.rb index 4e97268364..f04de9dfa3 100644 --- a/spec/controllers/admin_public_body_categories_controller_spec.rb +++ b/spec/controllers/admin_public_body_categories_controller_spec.rb @@ -102,7 +102,7 @@ expect { post :create, params: { :public_body_category => @params } - }.to change{ PublicBodyCategory.count }.from(0).to(1) + }.to change { PublicBodyCategory.count }.from(0).to(1) end it 'can create a category when the default locale is an underscore locale' do @@ -167,7 +167,7 @@ it 'saves the category' do expect { post :create, params: { :public_body_category => @params } - }.to change{ PublicBodyCategory.count }.from(0).to(1) + }.to change { PublicBodyCategory.count }.from(0).to(1) end it 'saves the default locale translation' do @@ -706,7 +706,7 @@ expect { post :destroy, params: { :id => category.id } - }.to change{ PublicBodyCategory.count }.from(1).to(0) + }.to change { PublicBodyCategory.count }.from(1).to(0) end it 'destroys non-empty public body categories' do @@ -718,7 +718,7 @@ expect { post :destroy, params: { :id => category.id } - }.to change{ PublicBodyCategory.count }.from(1).to(0) + }.to change { PublicBodyCategory.count }.from(1).to(0) end it 'notifies the admin that the category was destroyed' do diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb index 5faa4f92e9..c797b3626c 100644 --- a/spec/controllers/admin_public_body_controller_spec.rb +++ b/spec/controllers/admin_public_body_controller_spec.rb @@ -23,11 +23,11 @@ end describe 'GET #show' do - let(:public_body){ FactoryBot.create(:public_body) } - let(:info_request){ FactoryBot.create(:info_request, + let(:public_body) { FactoryBot.create(:public_body) } + let(:info_request) { FactoryBot.create(:info_request, :public_body => public_body) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } it "returns successfully" do get :show, params: { :id => public_body.id }, @@ -152,7 +152,7 @@ expected = existing + 1 expect { post :create, params: @params - }.to change{ PublicBody.count }.from(existing).to(expected) + }.to change { PublicBody.count }.from(existing).to(expected) end it 'can create a public body when the default locale is an underscore locale' do @@ -197,7 +197,7 @@ expected = existing + 1 expect { post :create, params: @params - }.to change{ PublicBody.count }.from(existing).to(expected) + }.to change { PublicBody.count }.from(existing).to(expected) end it 'saves the default locale translation' do diff --git a/spec/controllers/admin_public_body_headings_controller_spec.rb b/spec/controllers/admin_public_body_headings_controller_spec.rb index 1e58887a05..8fac505723 100644 --- a/spec/controllers/admin_public_body_headings_controller_spec.rb +++ b/spec/controllers/admin_public_body_headings_controller_spec.rb @@ -47,7 +47,7 @@ it 'creates a new heading in the default locale' do expect { post :create, params: { :public_body_heading => @params } - }.to change{ PublicBodyHeading.count }.from(0).to(1) + }.to change { PublicBodyHeading.count }.from(0).to(1) end it 'can create a heading when the default locale is an underscore locale' do @@ -92,7 +92,7 @@ it 'saves the heading' do expect { post :create, params: { :public_body_heading => @params } - }.to change{ PublicBodyHeading.count }.from(0).to(1) + }.to change { PublicBodyHeading.count }.from(0).to(1) end it 'saves the default locale translation' do @@ -490,7 +490,7 @@ expect { post :destroy, params: { :id => heading.id } - }.to change{ PublicBodyHeading.count }.from(1).to(0) + }.to change { PublicBodyHeading.count }.from(1).to(0) end it 'destroys a heading that has associated categories' do @@ -506,7 +506,7 @@ expect { post :destroy, params: { :id => heading.id } - }.to change{ PublicBodyHeading.count }.from(1).to(0) + }.to change { PublicBodyHeading.count }.from(1).to(0) end it 'notifies the admin that the heading was destroyed' do diff --git a/spec/controllers/admin_request_controller_spec.rb b/spec/controllers/admin_request_controller_spec.rb index ed742c8a57..12ba954f65 100644 --- a/spec/controllers/admin_request_controller_spec.rb +++ b/spec/controllers/admin_request_controller_spec.rb @@ -4,9 +4,9 @@ describe AdminRequestController, "when administering requests" do describe 'GET #index' do - let(:info_request){ FactoryBot.create(:info_request) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:info_request) { FactoryBot.create(:info_request) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } it "is successful" do get :index, session: { :user_id => admin_user.id } @@ -48,9 +48,9 @@ end context 'when passed a query' do - let!(:dog_request){ FactoryBot.create(:info_request, + let!(:dog_request) { FactoryBot.create(:info_request, :title => 'A dog request') } - let!(:cat_request){ FactoryBot.create(:info_request, + let!(:cat_request) { FactoryBot.create(:info_request, :title => 'A cat request') } it 'assigns info requests with titles matching the query to the view @@ -96,10 +96,10 @@ end describe 'GET #show' do - let(:info_request){ FactoryBot.create(:info_request) } - let(:external_request){ FactoryBot.create(:external_request) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:info_request) { FactoryBot.create(:info_request) } + let(:external_request) { FactoryBot.create(:external_request) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } render_views @@ -153,7 +153,7 @@ end describe 'GET #edit' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it "is successful" do get :edit, params: { :id => info_request } @@ -163,7 +163,7 @@ end describe 'PUT #update' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it "saves edits to a request" do post :update, params: { @@ -202,7 +202,7 @@ end describe 'DELETE #destroy' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'calls destroy on the info_request object' do allow(InfoRequest).to receive(:find). @@ -228,7 +228,7 @@ end describe 'POST #hide' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it "hides requests and sends a notification email that it has done so" do post :hide, params: { diff --git a/spec/controllers/admin_track_controller_spec.rb b/spec/controllers/admin_track_controller_spec.rb index 8ec44eb227..148887c4f4 100644 --- a/spec/controllers/admin_track_controller_spec.rb +++ b/spec/controllers/admin_track_controller_spec.rb @@ -11,7 +11,7 @@ end describe 'POST destroy' do - let(:track){ FactoryBot.create(:track_thing) } + let(:track) { FactoryBot.create(:track_thing) } it 'destroys the track' do post :destroy, params: { id: track.id } diff --git a/spec/controllers/admin_user_controller_spec.rb b/spec/controllers/admin_user_controller_spec.rb index 5c039d2812..d969a4d724 100644 --- a/spec/controllers/admin_user_controller_spec.rb +++ b/spec/controllers/admin_user_controller_spec.rb @@ -132,9 +132,9 @@ end describe 'GET #show' do - let(:info_request){ FactoryBot.create(:info_request) } - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_admin_user){ FactoryBot.create(:pro_admin_user) } + let(:info_request) { FactoryBot.create(:info_request) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } it "is successful" do get :show, params: { :id => FactoryBot.create(:user) }, @@ -230,7 +230,7 @@ describe "POST #update" do - let(:admin_user){ FactoryBot.create(:admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } before do allow(AlaveteliConfiguration).to receive(:skip_admin_auth).and_return(false) diff --git a/spec/controllers/alaveteli_pro/account_request_controller_spec.rb b/spec/controllers/alaveteli_pro/account_request_controller_spec.rb index a40064d3a5..d7dc05a7ab 100644 --- a/spec/controllers/alaveteli_pro/account_request_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/account_request_controller_spec.rb @@ -38,7 +38,7 @@ end describe "#create" do - let(:account_request_params){ { email: 'test@localhost', + let(:account_request_params) { { email: 'test@localhost', reason: 'Have a look around', marketing_emails: 'yes', training_emails: 'no' } } diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb index 197c391198..d39c229c54 100644 --- a/spec/controllers/general_controller_spec.rb +++ b/spec/controllers/general_controller_spec.rb @@ -308,20 +308,20 @@ it "should filter results based on end of URL being 'all'" do get :search, params: { :combined => "bob/all" } - expect(assigns[:xapian_requests].results.map{|x| x[:model]}).to match_array([ + expect(assigns[:xapian_requests].results.map {|x| x[:model]}).to match_array([ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), info_request_events(:useful_incoming_message_event), info_request_events(:another_useful_incoming_message_event), ]) - expect(assigns[:xapian_users].results.map{|x| x[:model]}).to eq([users(:bob_smith_user)]) + expect(assigns[:xapian_users].results.map {|x| x[:model]}).to eq([users(:bob_smith_user)]) expect(assigns[:xapian_bodies].results).to eq([]) end it "should filter results based on end of URL being 'users'" do get :search, params: { :combined => "bob/users" } expect(assigns[:xapian_requests]).to eq(nil) - expect(assigns[:xapian_users].results.map{|x| x[:model]}).to eq([users(:bob_smith_user)]) + expect(assigns[:xapian_users].results.map {|x| x[:model]}).to eq([users(:bob_smith_user)]) expect(assigns[:xapian_bodies]).to eq(nil) end @@ -338,7 +338,7 @@ it "should filter results based on end of URL being 'requests'" do get :search, params: { :combined => "bob/requests" } - expect(assigns[:xapian_requests].results.map{|x|x[:model]}).to match_array([ + expect(assigns[:xapian_requests].results.map {|x|x[:model]}).to match_array([ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), info_request_events(:useful_incoming_message_event), @@ -352,7 +352,7 @@ get :search, params: { :combined => "quango/bodies" } expect(assigns[:xapian_requests]).to eq(nil) expect(assigns[:xapian_users]).to eq(nil) - expect(assigns[:xapian_bodies].results.map{|x|x[:model]}).to eq([public_bodies(:geraldine_public_body)]) + expect(assigns[:xapian_bodies].results.map {|x|x[:model]}).to eq([public_bodies(:geraldine_public_body)]) end it 'should prioritise direct matches of public body names' do @@ -392,7 +392,7 @@ it "should not show unconfirmed users" do get :search, params: { :combined => "unconfirmed/users" } expect(response).to render_template('search') - expect(assigns[:xapian_users].results.map{|x|x[:model]}).to eq([]) + expect(assigns[:xapian_users].results.map {|x|x[:model]}).to eq([]) end it "should show newly-confirmed users" do @@ -403,7 +403,7 @@ get :search, params: { :combined => "unconfirmed/users" } expect(response).to render_template('search') - expect(assigns[:xapian_users].results.map{|x|x[:model]}).to eq([u]) + expect(assigns[:xapian_users].results.map {|x|x[:model]}).to eq([u]) end it "should show tracking links for requests-only searches" do diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index b71f22031a..17c9b14e9f 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -14,7 +14,7 @@ end describe 'GET #unhappy' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'shows the unhappy template' do get :unhappy @@ -127,7 +127,7 @@ end context 'when a last_request_id cookie is set' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } context "when the user can access the specified request" do it 'assigns @last_request' do @@ -156,7 +156,7 @@ end context 'when a last_body_id cookie is set' do - let(:body){ FactoryBot.create(:public_body) } + let(:body) { FactoryBot.create(:public_body) } it 'assigns @last_body' do request.cookies["last_body_id"] = body.id diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb index 5b3d9a241f..4020e948b8 100644 --- a/spec/controllers/public_body_controller_spec.rb +++ b/spec/controllers/public_body_controller_spec.rb @@ -29,7 +29,7 @@ it "should assign the requests (1)" do get :show, params: { :url_name => "tgq", :view => 'all' } conditions = { :public_body_id => public_bodies(:geraldine_public_body).id } - actual = assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + actual = assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array(InfoRequest.where(conditions)) end @@ -37,14 +37,14 @@ get :show, params: { :url_name => "tgq", :view => 'successful' } conditions = { :described_state => 'successful', :public_body_id => public_bodies(:geraldine_public_body).id } - actual = assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + actual = assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array(InfoRequest.where(conditions)) end it "should assign the requests (3)" do get :show, params: { :url_name => "dfh", :view => 'all' } conditions = { :public_body_id => public_bodies(:humpadink_public_body).id } - actual = assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + actual = assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array(InfoRequest.where(conditions)) end @@ -422,7 +422,7 @@ def make_single_language_example(locale) it "only includes visible bodies" do get :list_all_csv all_data = CSV.parse(response.body) - expect(all_data.any?{ |row| row.include?('Internal admin authority') }).to be false + expect(all_data.any? { |row| row.include?('Internal admin authority') }).to be false end it "does not include site_administration bodies" do @@ -433,7 +433,7 @@ def make_single_language_example(locale) get :list_all_csv all_data = CSV.parse(response.body) - expect(all_data.any?{ |row| row.include?('Site Admin Body') }).to be false + expect(all_data.any? { |row| row.include?('Site Admin Body') }).to be false end end diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb index bda6b39637..e2e56a949e 100644 --- a/spec/controllers/reports_controller_spec.rb +++ b/spec/controllers/reports_controller_spec.rb @@ -4,8 +4,8 @@ describe ReportsController do describe 'POST #create' do - let(:info_request){ FactoryBot.create(:info_request) } - let(:user){ FactoryBot.create(:user) } + let(:info_request) { FactoryBot.create(:info_request) } + let(:user) { FactoryBot.create(:user) } context "when reporting a request when not logged in" do it "should only allow logged-in users to report requests" do @@ -307,8 +307,8 @@ end describe "GET #new" do - let(:info_request){ FactoryBot.create(:info_request) } - let(:user){ FactoryBot.create(:user) } + let(:info_request) { FactoryBot.create(:info_request) } + let(:user) { FactoryBot.create(:user) } context "not logged in" do it "should require the user to be logged in" do diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 2ef49b0623..3dff44960e 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -670,7 +670,7 @@ def get_attachment(params = {}) describe RequestController do describe 'GET get_attachment_as_html' do - let(:info_request){ FactoryBot.create(:info_request_with_incoming_attachments) } + let(:info_request) { FactoryBot.create(:info_request_with_incoming_attachments) } def get_html_attachment(params = {}) default_params = { :incoming_message_id => @@ -2062,7 +2062,7 @@ def expect_hidden(hidden_template) describe "POST describe_state" do describe 'if the request is external' do - let(:external_request){ FactoryBot.create(:external_request) } + let(:external_request) { FactoryBot.create(:external_request) } it 'should redirect to the request page' do patch :describe_state, params: { :id => external_request.id } @@ -2074,7 +2074,7 @@ def expect_hidden(hidden_template) describe 'when the request is internal' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } def post_status(status, info_request) patch :describe_state, @@ -2090,10 +2090,10 @@ def post_status(status, info_request) context 'when the request is embargoed' do - let(:info_request){ FactoryBot.create(:embargoed_request) } + let(:info_request) { FactoryBot.create(:embargoed_request) } it 'should raise ActiveRecord::NotFound' do - expect{ post_status('rejected', info_request) } + expect { post_status('rejected', info_request) } .to raise_error ActiveRecord::RecordNotFound end end @@ -2112,7 +2112,7 @@ def post_status(status, info_request) describe 'when the request is old and unclassified' do - let(:info_request){ FactoryBot.create(:old_unclassified_request)} + let(:info_request) { FactoryBot.create(:old_unclassified_request)} describe 'when the user is not logged in' do @@ -2127,7 +2127,7 @@ def post_status(status, info_request) describe 'when the user is logged in as a different user' do - let(:other_user){ FactoryBot.create(:user) } + let(:other_user) { FactoryBot.create(:user) } before do session[:user_id] = other_user.id @@ -2241,8 +2241,8 @@ def post_status(status, info_request) describe 'when logged in as an admin user who is not the actual requester' do - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:info_request){ FactoryBot.create(:info_request) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:info_request) { FactoryBot.create(:info_request) } before do session[:user_id] = admin_user.id @@ -2292,8 +2292,8 @@ def post_status(status, info_request) describe 'when logged in as an admin user who is also the actual requester' do - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:info_request){ FactoryBot.create(:info_request, :user => admin_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:info_request) { FactoryBot.create(:info_request, :user => admin_user) } before do session[:user_id] = admin_user.id @@ -2462,7 +2462,7 @@ def post_status(status, info_request) render_views - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } before do session[:user_id] = info_request.user_id @@ -2539,7 +2539,7 @@ def expect_redirect(status, redirect_path) context 'when there is a last response' do - let(:info_request){ FactoryBot.create(:info_request_with_incoming) } + let(:info_request) { FactoryBot.create(:info_request_with_incoming) } it 'should redirect to the "response url"' do session[:user_id] = info_request.user_id @@ -2589,7 +2589,7 @@ def expect_redirect(status, redirect_path) context 'when status is updated to "gone postal"' do - let(:info_request){ FactoryBot.create(:info_request_with_incoming) } + let(:info_request) { FactoryBot.create(:info_request_with_incoming) } it 'should redirect to the "respond to last" url' do session[:user_id] = info_request.user_id @@ -2682,7 +2682,7 @@ def expect_redirect(status, redirect_path) context 'when status is updated to "user_withdrawn"' do - let(:info_request){ FactoryBot.create(:info_request_with_incoming) } + let(:info_request) { FactoryBot.create(:info_request_with_incoming) } it 'should redirect to the "respond to last" url' do session[:user_id] = info_request.user_id @@ -2744,7 +2744,7 @@ def expect_redirect(status, redirect_path) end context 'when the request is embargoed' do - let(:embargoed_request){ FactoryBot.create(:embargoed_request)} + let(:embargoed_request) { FactoryBot.create(:embargoed_request)} it 'raises an ActiveRecord::RecordNotFound error' do expect { @@ -2885,7 +2885,7 @@ def expect_redirect(status, redirect_path) load_raw_emails_data end - let(:badger_request){ info_requests(:badger_request) } + let(:badger_request) { info_requests(:badger_request) } it "renders the 'similar' template" do get :similar, params: { @@ -2906,8 +2906,8 @@ def expect_redirect(status, redirect_path) # Xapian seems to think *all* the requests are similar results = assigns[:xapian_object].results - expected = InfoRequest.all.reject{ |request| request == badger_request } - expect(results.map{ |result| result[:model].info_request }) + expected = InfoRequest.all.reject { |request| request == badger_request } + expect(results.map { |result| result[:model].info_request }) .to match_array(expected) end @@ -3302,7 +3302,7 @@ def make_request describe 'GET #details' do - let(:info_request){ FactoryBot.create(:info_request)} + let(:info_request) { FactoryBot.create(:info_request)} it 'renders the details template' do get :details, params: { :url_title => info_request.url_title } @@ -3364,7 +3364,7 @@ def make_request describe RequestController do describe 'GET #describe_state_message' do - let(:info_request){ FactoryBot.create(:info_request_with_incoming) } + let(:info_request) { FactoryBot.create(:info_request_with_incoming) } it 'assigns the info_request to the view' do get :describe_state_message, params: { @@ -3400,7 +3400,7 @@ def make_request end context 'when the request is embargoed' do - let(:info_request){ FactoryBot.create(:embargoed_request) } + let(:info_request) { FactoryBot.create(:embargoed_request) } it 'raises ActiveRecord::RecordNotFound' do expect { @@ -3485,7 +3485,7 @@ def make_request describe 'GET #show_request_event' do context 'when the event is an incoming message' do - let(:event){ FactoryBot.create(:response_event) } + let(:event) { FactoryBot.create(:response_event) } it 'returns a 301 status' do get :show_request_event, params: { :info_request_event_id => event.id } @@ -3507,7 +3507,7 @@ def make_request end context 'when the event is an outgoing message' do - let(:event){ FactoryBot.create(:sent_event) } + let(:event) { FactoryBot.create(:sent_event) } it 'returns a 301 status' do get :show_request_event, params: { :info_request_event_id => event.id } @@ -3529,7 +3529,7 @@ def make_request end context 'for any other kind of event' do - let(:event){ FactoryBot.create(:info_request_event) } + let(:event) { FactoryBot.create(:info_request_event) } it 'returns a 301 status' do get :show_request_event, params: { :info_request_event_id => event.id } diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index c074f493ec..8c102c0313 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -170,7 +170,7 @@ def make_request } actual = - assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array([info_requests(:naughty_chicken_request)]) end @@ -357,7 +357,7 @@ def make_request } actual = - assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array([request_1]) end @@ -538,7 +538,7 @@ def make_request } actual = - assigns[:xapian_requests].results.map{ |x| x[:model].info_request } + assigns[:xapian_requests].results.map { |x| x[:model].info_request } expect(actual).to match_array([request_1]) end @@ -749,7 +749,7 @@ def make_request end context 'when the user is already signed in' do - let(:user){ FactoryBot.create(:user) } + let(:user) { FactoryBot.create(:user) } before do ActionController::Base.allow_forgery_protection = true diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index ae6e6ca975..8e312f278c 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -190,7 +190,7 @@ def do_signin(email, password) end context 'if the user is already signed in' do - let(:user){ FactoryBot.create(:user) } + let(:user) { FactoryBot.create(:user) } before do ActionController::Base.allow_forgery_protection = true diff --git a/spec/controllers/widget_votes_controller_spec.rb b/spec/controllers/widget_votes_controller_spec.rb index 9cbc3cb9d0..4dc4ddb499 100644 --- a/spec/controllers/widget_votes_controller_spec.rb +++ b/spec/controllers/widget_votes_controller_spec.rb @@ -6,7 +6,7 @@ include LinkToHelper describe 'POST #create' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } before do allow(AlaveteliConfiguration).to receive(:enable_widgets).and_return(true) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 601b238bad..c3ce4c7f12 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -31,7 +31,7 @@ describe '#read_asset_file' do it "raises an Exception if it can't find the file" do - expect{ read_asset_file('nosuchfile.css') }. + expect { read_asset_file('nosuchfile.css') }. to raise_error(Sprockets::FileNotFound, "Asset file 'nosuchfile.css' was not found in the " \ "assets directory") diff --git a/spec/helpers/info_request_helper_spec.rb b/spec/helpers/info_request_helper_spec.rb index 5c33f822d4..af92ae7798 100644 --- a/spec/helpers/info_request_helper_spec.rb +++ b/spec/helpers/info_request_helper_spec.rb @@ -580,10 +580,10 @@ end describe '#attachment_link' do - let(:incoming_message){ FactoryBot.create(:incoming_message) } + let(:incoming_message) { FactoryBot.create(:incoming_message) } context 'if an icon exists for the filetype' do - let(:jpeg_attachment){ FactoryBot.create(:jpeg_attachment, + let(:jpeg_attachment) { FactoryBot.create(:jpeg_attachment, :incoming_message => incoming_message, :url_part_number => 1) } @@ -597,7 +597,7 @@ end context 'if no icon exists for the filetype' do - let(:unknown_attachment){ FactoryBot.create(:unknown_attachment, + let(:unknown_attachment) { FactoryBot.create(:unknown_attachment, :incoming_message => incoming_message, :url_part_number => 1) } @@ -612,8 +612,8 @@ end describe '#attachment_path' do - let(:incoming_message){ FactoryBot.create(:incoming_message) } - let(:jpeg_attachment){ FactoryBot.create(:jpeg_attachment, + let(:incoming_message) { FactoryBot.create(:incoming_message) } + let(:jpeg_attachment) { FactoryBot.create(:jpeg_attachment, :incoming_message => incoming_message, :url_part_number => 1) } diff --git a/spec/integration/alaveteli_dsl.rb b/spec/integration/alaveteli_dsl.rb index ff002cb4a6..c915f1fd18 100644 --- a/spec/integration/alaveteli_dsl.rb +++ b/spec/integration/alaveteli_dsl.rb @@ -163,7 +163,7 @@ def cache_directories_exist?(request) AlaveteliLocalization.available_locales.each do |locale| paths << File.join(cache_path, locale, 'request', request.request_dirs) end - paths.any?{ |path| File.exist?(path) } + paths.any? { |path| File.exist?(path) } end def with_forgery_protection diff --git a/spec/integration/alaveteli_pro/request_list_spec.rb b/spec/integration/alaveteli_pro/request_list_spec.rb index dc6989efe8..b36b05f4e0 100644 --- a/spec/integration/alaveteli_pro/request_list_spec.rb +++ b/spec/integration/alaveteli_pro/request_list_spec.rb @@ -4,7 +4,7 @@ describe "pro request list" do let(:pro_user) { FactoryBot.create(:pro_user) } - let(:public_body){ FactoryBot.create(:public_body) } + let(:public_body) { FactoryBot.create(:public_body) } let!(:pro_user_session) { login(pro_user) } let!(:info_requests) do FactoryBot.create_list(:info_request, diff --git a/spec/integration/download_request_spec.rb b/spec/integration/download_request_spec.rb index ab24ed85eb..2b8badc9ea 100644 --- a/spec/integration/download_request_spec.rb +++ b/spec/integration/download_request_spec.rb @@ -438,7 +438,7 @@ def sleep_and_receive_mail(name, info_request) it 'should successfully make a zipfile for an external request' do external_request = FactoryBot.create(:external_request) user = login(FactoryBot.create(:user)) - inspect_zip_download(user, external_request){ |zip| expect(zip.count).to eq(1) } + inspect_zip_download(user, external_request) { |zip| expect(zip.count).to eq(1) } end end diff --git a/spec/integration/incoming_mail_spec.rb b/spec/integration/incoming_mail_spec.rb index f2f54a7cff..bed103e90f 100644 --- a/spec/integration/incoming_mail_spec.rb +++ b/spec/integration/incoming_mail_spec.rb @@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/alaveteli_dsl') describe 'when handling incoming mail' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it "receives incoming messages, sends email to requester, and shows them" do receive_incoming_mail('incoming-request-plain.email', diff --git a/spec/integration/signin_spec.rb b/spec/integration/signin_spec.rb index 47bc9d8c2a..da9c9c946e 100644 --- a/spec/integration/signin_spec.rb +++ b/spec/integration/signin_spec.rb @@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/alaveteli_dsl') describe "Signing in" do - let(:user){ FactoryBot.create(:user) } + let(:user) { FactoryBot.create(:user) } def try_login(user, options = {}) default_options = { :email => user.email, diff --git a/spec/integration/view_request_spec.rb b/spec/integration/view_request_spec.rb index d7da4c3dce..5866623d78 100644 --- a/spec/integration/view_request_spec.rb +++ b/spec/integration/view_request_spec.rb @@ -42,7 +42,7 @@ info_request = FactoryBot.create(:info_request_with_incoming_attachments) incoming_message = info_request.incoming_messages.first attachment_url = "/es/request/#{info_request.id}/response/#{incoming_message.id}/attach/2/interesting.pdf" - using_session(non_owner){ visit(attachment_url) } + using_session(non_owner) { visit(attachment_url) } expect(cache_directories_exist?(info_request)).to be true # Admin makes the incoming message requester only diff --git a/spec/lib/alaveteli_text_masker_spec.rb b/spec/lib/alaveteli_text_masker_spec.rb index be0861de48..7002b8e22b 100644 --- a/spec/lib/alaveteli_text_masker_spec.rb +++ b/spec/lib/alaveteli_text_masker_spec.rb @@ -127,7 +127,7 @@ def pdf_replacement_test(use_ghostscript_compression) it 'keeps the uncensored original if uncompression of a PDF fails' do orig_pdf = load_file_fixture('tfl.pdf') pdf = orig_pdf.dup - allow(class_instance).to receive(:uncompress_pdf){ nil } + allow(class_instance).to receive(:uncompress_pdf) { nil } result = class_instance.apply_masks(pdf, "application/pdf") expect(result).to eq(orig_pdf) end @@ -135,8 +135,8 @@ def pdf_replacement_test(use_ghostscript_compression) it 'uses the uncompressed PDF text if re-compression of a compressed PDF fails' do orig_pdf = load_file_fixture('tfl.pdf') pdf = orig_pdf.dup - allow(class_instance).to receive(:uncompress_pdf){ "something about foi@tfl.gov.uk" } - allow(class_instance).to receive(:compress_pdf){ nil } + allow(class_instance).to receive(:uncompress_pdf) { "something about foi@tfl.gov.uk" } + allow(class_instance).to receive(:compress_pdf) { nil } result = class_instance.apply_masks(pdf, "application/pdf") expect(result).to match "something about xxx@xxx.xxx.xx" end diff --git a/spec/lib/health_checks/health_checkable_spec.rb b/spec/lib/health_checks/health_checkable_spec.rb index d69e7e0c7a..10c09bb5cb 100644 --- a/spec/lib/health_checks/health_checkable_spec.rb +++ b/spec/lib/health_checks/health_checkable_spec.rb @@ -35,7 +35,7 @@ class MockCheck describe '#ok?' do it 'is intended to be overridden by the includer' do - expect{ @subject.ok? }.to raise_error(NotImplementedError) + expect { @subject.ok? }.to raise_error(NotImplementedError) end end diff --git a/spec/lib/mail_handler/mail_handler_spec.rb b/spec/lib/mail_handler/mail_handler_spec.rb index 5b7ff4de37..a6ef151614 100644 --- a/spec/lib/mail_handler/mail_handler_spec.rb +++ b/spec/lib/mail_handler/mail_handler_spec.rb @@ -81,7 +81,7 @@ def create_message_from(from_field) it 'should not error on a subject line with an encoding encoding not recognized by iconv' do mail = get_fixture_mail('unrecognized-encoding-mail.email') - expect{ mail.subject }.not_to raise_error + expect { mail.subject }.not_to raise_error end end @@ -285,7 +285,7 @@ def expect_content_type(fixture_file, content_type) it 'should correctly return the types in an example bounce report' do mail = get_fixture_mail('track-response-ms-bounce.email') - report = mail.parts.detect{ |part| MailHandler.get_content_type(part) == 'multipart/report'} + report = mail.parts.detect { |part| MailHandler.get_content_type(part) == 'multipart/report'} expect(MailHandler.get_content_type(report.parts[0])).to eq('text/plain') expect(MailHandler.get_content_type(report.parts[1])).to eq('message/delivery-status') expect(MailHandler.get_content_type(report.parts[2])).to eq('message/rfc822') diff --git a/spec/lib/typeahead_search_spec.rb b/spec/lib/typeahead_search_spec.rb index 8e380ea952..c07d8357a3 100644 --- a/spec/lib/typeahead_search_spec.rb +++ b/spec/lib/typeahead_search_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe TypeaheadSearch do - let(:options){ { :model => InfoRequestEvent } } + let(:options) { { :model => InfoRequestEvent } } describe "#initialize" do @@ -97,11 +97,11 @@ end def search_info_requests(xapian_search) - xapian_search.results.map{ |result| result[:model].info_request } + xapian_search.results.map { |result| result[:model].info_request } end def search_bodies(xapian_search) - xapian_search.results.map{ |result| result[:model] } + xapian_search.results.map { |result| result[:model] } end it "returns nil for the empty query string" do diff --git a/spec/lib/user_spam_scorer_spec.rb b/spec/lib/user_spam_scorer_spec.rb index 3631e457ad..799ddd1982 100644 --- a/spec/lib/user_spam_scorer_spec.rb +++ b/spec/lib/user_spam_scorer_spec.rb @@ -292,7 +292,7 @@ :track_things => [] } user = mock_model(User, user_attrs) scorer = described_class.new(:score_mappings => { :invalid_method => 1 }) - expect{ scorer.score(user) }.to raise_error(NoMethodError) + expect { scorer.score(user) }.to raise_error(NoMethodError) end end diff --git a/spec/mailers/alaveteli_pro/embargo_mailer_spec.rb b/spec/mailers/alaveteli_pro/embargo_mailer_spec.rb index de5faf8529..f997a58666 100644 --- a/spec/mailers/alaveteli_pro/embargo_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/embargo_mailer_spec.rb @@ -34,8 +34,8 @@ AlaveteliPro::EmbargoMailer.alert_expiring mails = ActionMailer::Base.deliveries expect(mails.size).to eq 2 - first_mail = mails.detect{ |mail| mail.to == [pro_user.email] } - second_mail = mails.detect{ |mail| mail.to == [pro_user_2.email] } + first_mail = mails.detect { |mail| mail.to == [pro_user.email] } + second_mail = mails.detect { |mail| mail.to == [pro_user_2.email] } expect(first_mail).not_to be nil expect(second_mail).not_to be nil end @@ -58,7 +58,7 @@ time_travel_to(AlaveteliPro::Embargo.three_months_from_now - 3.days) do AlaveteliPro::EmbargoMailer.alert_expiring mails = ActionMailer::Base.deliveries - expect(mails.detect{ |mail| mail.to == [pro_user_2.email] }). + expect(mails.detect { |mail| mail.to == [pro_user_2.email] }). not_to be_nil end end @@ -104,7 +104,7 @@ AlaveteliPro::EmbargoMailer.alert_expiring mails = ActionMailer::Base.deliveries - mail = mails.detect{ |mail| mail.to == [pro_user_3.email] } + mail = mails.detect { |mail| mail.to == [pro_user_3.email] } expect(mail).to be nil end end @@ -169,8 +169,8 @@ AlaveteliPro::EmbargoMailer.alert_expired mails = ActionMailer::Base.deliveries expect(mails.size).to eq 2 - first_mail = mails.detect{ |mail| mail.to == [pro_user.email] } - second_mail = mails.detect{ |mail| mail.to == [pro_user_2.email] } + first_mail = mails.detect { |mail| mail.to == [pro_user.email] } + second_mail = mails.detect { |mail| mail.to == [pro_user_2.email] } expect(first_mail).not_to be nil expect(second_mail).not_to be nil end @@ -229,7 +229,7 @@ AlaveteliPro::EmbargoMailer.alert_expired mails = ActionMailer::Base.deliveries - mail = mails.detect{ |mail| mail.to == [pro_user_3.email] } + mail = mails.detect { |mail| mail.to == [pro_user_3.email] } expect(mail).to be nil end end diff --git a/spec/mailers/application_mailer_spec.rb b/spec/mailers/application_mailer_spec.rb index 4a9db0833d..209147b4bc 100644 --- a/spec/mailers/application_mailer_spec.rb +++ b/spec/mailers/application_mailer_spec.rb @@ -16,7 +16,7 @@ def set_base_views def add_mail_methods(method_names) @previous_layout = ApplicationMailer._layout.dup ApplicationMailer.send(:layout, nil) - method_names.each{ |method_name| ApplicationMailer.send(:define_method, method_name){ mail } } + method_names.each { |method_name| ApplicationMailer.send(:define_method, method_name) { mail } } end def remove_mail_methods(method_names) @@ -82,7 +82,7 @@ def create_multipart_method(method_name) neither core nor theme' do prepend_theme_views('theme_one') @mail = ApplicationMailer.neither - expect{ @mail.body }.to raise_error(ActionView::MissingTemplate) + expect { @mail.body }.to raise_error(ActionView::MissingTemplate) end it 'should render a multipart email using a theme template' do @@ -129,7 +129,7 @@ def create_multipart_method(method_name) neither core nor theme' do append_theme_views('theme_one') @mail = ApplicationMailer.neither - expect{ @mail.body }.to raise_error(ActionView::MissingTemplate) + expect { @mail.body }.to raise_error(ActionView::MissingTemplate) end it 'should render a multipart email using a core template' do diff --git a/spec/mailers/request_mailer_spec.rb b/spec/mailers/request_mailer_spec.rb index 6e211a45c1..4373ae1217 100644 --- a/spec/mailers/request_mailer_spec.rb +++ b/spec/mailers/request_mailer_spec.rb @@ -320,7 +320,7 @@ def sent_alert_params(request, type) old_request.save! expected_message = "internal error, no last response while making alert " \ "new response reminder, request id #{old_request.id}" - expect{ send_alerts }.to raise_error(expected_message) + expect { send_alerts }.to raise_error(expected_message) end context 'if the request is embargoed' do @@ -600,7 +600,7 @@ def sent_alert_params(request, type) end def kitten_mails - ActionMailer::Base.deliveries.select{ |mail| mail.body =~ /kitten/ } + ActionMailer::Base.deliveries.select { |mail| mail.body =~ /kitten/ } end it 'should not create HTML entities in the subject line' do diff --git a/spec/mailers/track_mailer_spec.rb b/spec/mailers/track_mailer_spec.rb index b752e95bbf..f5eb745322 100644 --- a/spec/mailers/track_mailer_spec.rb +++ b/spec/mailers/track_mailer_spec.rb @@ -113,7 +113,7 @@ it 'should raise an error if a non-event class is returned by the tracking query' do allow(@xapian_search).to receive(:results).and_return([{:model => 'string class'}]) - expect{ TrackMailer.alert_tracks }.to raise_error('need to add other types to TrackMailer.alert_tracks (unalerted)') + expect { TrackMailer.alert_tracks }.to raise_error('need to add other types to TrackMailer.alert_tracks (unalerted)') end it 'should record that a tracking email has been sent for each event that diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 0ac5096048..ee2c312a8d 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -911,7 +911,7 @@ let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } context 'when the request is embargoed' do - let(:info_request){ FactoryBot.create(:embargoed_request) } + let(:info_request) { FactoryBot.create(:embargoed_request) } it 'allows a pro admin user to administer' do with_feature_enabled(:alaveteli_pro) do @@ -951,7 +951,7 @@ end context 'when the request is not embargoed' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'allows a pro admin user to administer' do with_feature_enabled(:alaveteli_pro) do @@ -998,8 +998,8 @@ let(:pro_admin_user) { FactoryBot.create(:pro_admin_user) } context "when the comment's request is embargoed" do - let(:info_request){ FactoryBot.create(:embargoed_request) } - let(:comment){ FactoryBot.create(:comment, + let(:info_request) { FactoryBot.create(:embargoed_request) } + let(:comment) { FactoryBot.create(:comment, :info_request => info_request) } it 'allows a pro admin user to administer' do @@ -1040,8 +1040,8 @@ end context 'when the request is not embargoed' do - let(:info_request){ FactoryBot.create(:info_request) } - let(:comment){ FactoryBot.create(:comment, + let(:info_request) { FactoryBot.create(:info_request) } + let(:comment) { FactoryBot.create(:comment, :info_request => info_request) } it 'allows a pro admin user to administer' do diff --git a/spec/models/alaveteli_pro/activity_list/comment_spec.rb b/spec/models/alaveteli_pro/activity_list/comment_spec.rb index bc688d4d67..0c4d4194b5 100644 --- a/spec/models/alaveteli_pro/activity_list/comment_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/comment_spec.rb @@ -4,10 +4,10 @@ describe AlaveteliPro::ActivityList::Comment do include Rails.application.routes.url_helpers - let!(:user){ FactoryBot.create(:user) } - let!(:comment){ FactoryBot.create(:comment, :user => user) } - let!(:event){ FactoryBot.create(:comment_event, :comment => comment) } - let!(:activity){ described_class.new(event) } + let!(:user) { FactoryBot.create(:user) } + let!(:comment) { FactoryBot.create(:comment, :user => user) } + let!(:event) { FactoryBot.create(:comment_event, :comment => comment) } + let!(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/embargo_expiry_spec.rb b/spec/models/alaveteli_pro/activity_list/embargo_expiry_spec.rb index de0d41d427..1e1a7a9f31 100644 --- a/spec/models/alaveteli_pro/activity_list/embargo_expiry_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/embargo_expiry_spec.rb @@ -4,10 +4,10 @@ describe AlaveteliPro::ActivityList::EmbargoExpiry do include Rails.application.routes.url_helpers - let!(:user){ FactoryBot.create(:user) } - let!(:info_request){ FactoryBot.create(:info_request, :user => user) } - let!(:event){ FactoryBot.create(:expire_embargo_event, :info_request => info_request) } - let!(:activity){ described_class.new(event) } + let!(:user) { FactoryBot.create(:user) } + let!(:info_request) { FactoryBot.create(:info_request, :user => user) } + let!(:event) { FactoryBot.create(:expire_embargo_event, :info_request => info_request) } + let!(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/followup_resent_spec.rb b/spec/models/alaveteli_pro/activity_list/followup_resent_spec.rb index d8c353063e..8e91872d80 100644 --- a/spec/models/alaveteli_pro/activity_list/followup_resent_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/followup_resent_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::FollowupResent do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:followup_resent_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:followup_resent_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/followup_sent_spec.rb b/spec/models/alaveteli_pro/activity_list/followup_sent_spec.rb index 9c88366555..46b0aae509 100644 --- a/spec/models/alaveteli_pro/activity_list/followup_sent_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/followup_sent_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::FollowupSent do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:followup_sent_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:followup_sent_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/item_spec.rb b/spec/models/alaveteli_pro/activity_list/item_spec.rb index fc0a275796..c1494618d3 100644 --- a/spec/models/alaveteli_pro/activity_list/item_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/item_spec.rb @@ -5,7 +5,7 @@ describe '.new' do it 'requires an event argument' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the event argument' do diff --git a/spec/models/alaveteli_pro/activity_list/list_spec.rb b/spec/models/alaveteli_pro/activity_list/list_spec.rb index f665f7b552..e72fac99ac 100644 --- a/spec/models/alaveteli_pro/activity_list/list_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/list_spec.rb @@ -5,7 +5,7 @@ describe '.new' do it 'requires a user, page and per_page arguments' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the user, page and per_page arguments' do @@ -19,7 +19,7 @@ end describe '#event_types' do - let(:user){ FactoryBot.create(:user) } + let(:user) { FactoryBot.create(:user) } it 'returns an array' do expect(described_class.new(user, 1, 10).event_types.class).to eq Array diff --git a/spec/models/alaveteli_pro/activity_list/new_response_spec.rb b/spec/models/alaveteli_pro/activity_list/new_response_spec.rb index 70d1f559fd..86bc6ce7bc 100644 --- a/spec/models/alaveteli_pro/activity_list/new_response_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/new_response_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::NewResponse do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:response_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:response_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/overdue_spec.rb b/spec/models/alaveteli_pro/activity_list/overdue_spec.rb index e846f11688..18d177e744 100644 --- a/spec/models/alaveteli_pro/activity_list/overdue_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/overdue_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::Overdue do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:overdue_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:overdue_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/request_resent_spec.rb b/spec/models/alaveteli_pro/activity_list/request_resent_spec.rb index dcbde0bef1..15180c928f 100644 --- a/spec/models/alaveteli_pro/activity_list/request_resent_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/request_resent_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::RequestResent do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:resent_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:resent_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/request_sent_spec.rb b/spec/models/alaveteli_pro/activity_list/request_sent_spec.rb index 6f1bd36d66..793a3fc695 100644 --- a/spec/models/alaveteli_pro/activity_list/request_sent_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/request_sent_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::RequestSent do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:sent_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:sent_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/activity_list/very_overdue_spec.rb b/spec/models/alaveteli_pro/activity_list/very_overdue_spec.rb index f521f47df9..ef0bc2435b 100644 --- a/spec/models/alaveteli_pro/activity_list/very_overdue_spec.rb +++ b/spec/models/alaveteli_pro/activity_list/very_overdue_spec.rb @@ -4,8 +4,8 @@ describe AlaveteliPro::ActivityList::VeryOverdue do include Rails.application.routes.url_helpers - let(:event){ FactoryBot.create(:very_overdue_event) } - let(:activity){ described_class.new(event) } + let(:event) { FactoryBot.create(:very_overdue_event) } + let(:activity) { described_class.new(event) } describe '#description' do diff --git a/spec/models/alaveteli_pro/request_filter_spec.rb b/spec/models/alaveteli_pro/request_filter_spec.rb index 84b9ff233e..d4f21dca50 100644 --- a/spec/models/alaveteli_pro/request_filter_spec.rb +++ b/spec/models/alaveteli_pro/request_filter_spec.rb @@ -134,7 +134,7 @@ def expect_label(label, filter) end describe '#results' do - let(:user){ FactoryBot.create(:user) } + let(:user) { FactoryBot.create(:user) } context 'when no attributes are supplied' do diff --git a/spec/models/alaveteli_pro/to_do_list/item_spec.rb b/spec/models/alaveteli_pro/to_do_list/item_spec.rb index f404ec0e5e..b6674b97dd 100644 --- a/spec/models/alaveteli_pro/to_do_list/item_spec.rb +++ b/spec/models/alaveteli_pro/to_do_list/item_spec.rb @@ -6,7 +6,7 @@ describe '.new' do it 'requires a user' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the user' do diff --git a/spec/models/alaveteli_pro/to_do_list/list_spec.rb b/spec/models/alaveteli_pro/to_do_list/list_spec.rb index 12e76e3061..8feff8072e 100644 --- a/spec/models/alaveteli_pro/to_do_list/list_spec.rb +++ b/spec/models/alaveteli_pro/to_do_list/list_spec.rb @@ -6,7 +6,7 @@ describe '.new' do it 'requires a user' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the user' do diff --git a/spec/models/alaveteli_pro/to_do_list/very_overdue_request_spec.rb b/spec/models/alaveteli_pro/to_do_list/very_overdue_request_spec.rb index 4ab097767e..7e0d91b387 100644 --- a/spec/models/alaveteli_pro/to_do_list/very_overdue_request_spec.rb +++ b/spec/models/alaveteli_pro/to_do_list/very_overdue_request_spec.rb @@ -8,7 +8,7 @@ let(:user) { info_request.user } before do - time_travel_to(Time.zone.parse('2015-11-01')){ info_request } + time_travel_to(Time.zone.parse('2015-11-01')) { info_request } AlaveteliPro::RequestSummary.create_or_update_from(info_request) @very_overdue_request = described_class.new(user) end diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb index c130eb0727..a31c0f96e5 100644 --- a/spec/models/incoming_message_spec.rb +++ b/spec/models/incoming_message_spec.rb @@ -349,7 +349,7 @@ :url_part_number => 3) message.reload - expect{ message._extract_text }. + expect { message._extract_text }. to_not raise_error end end @@ -1040,7 +1040,7 @@ def populate_raw_email(fixture) "to implement clipping like for attachment " \ "text, or there is some other MIME decoding " \ "problem or similar" - expect{ @incoming_message.get_main_body_text_unfolded }. + expect { @incoming_message.get_main_body_text_unfolded }. to raise_error(RuntimeError, expected_text) end diff --git a/spec/models/info_request/prominence/calculator_spec.rb b/spec/models/info_request/prominence/calculator_spec.rb index 6820378b8a..3d6c933944 100644 --- a/spec/models/info_request/prominence/calculator_spec.rb +++ b/spec/models/info_request/prominence/calculator_spec.rb @@ -3,8 +3,8 @@ describe InfoRequest::Prominence::Calculator do - let(:info_request){ FactoryBot.build(:info_request) } - let(:embargoed_request){ FactoryBot.create(:embargoed_request) } + let(:info_request) { FactoryBot.build(:info_request) } + let(:embargoed_request) { FactoryBot.create(:embargoed_request) } def expect_value(prominence, method, value) info_request.prominence = prominence diff --git a/spec/models/info_request/response_gatekeeper/authority_only_spec.rb b/spec/models/info_request/response_gatekeeper/authority_only_spec.rb index af5411294a..23ba866c16 100644 --- a/spec/models/info_request/response_gatekeeper/authority_only_spec.rb +++ b/spec/models/info_request/response_gatekeeper/authority_only_spec.rb @@ -13,7 +13,7 @@ it 'requires an email' do gatekeeper = described_class.new(FactoryBot.build(:info_request)) - expect{ gatekeeper.allow? }.to raise_error(ArgumentError) + expect { gatekeeper.allow? }.to raise_error(ArgumentError) end context 'if the email has no From address' do diff --git a/spec/models/info_request/response_gatekeeper/base_spec.rb b/spec/models/info_request/response_gatekeeper/base_spec.rb index a8ab78dd4b..40a61c4cad 100644 --- a/spec/models/info_request/response_gatekeeper/base_spec.rb +++ b/spec/models/info_request/response_gatekeeper/base_spec.rb @@ -6,7 +6,7 @@ describe '.new' do it 'requires an info_request' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the info_request' do @@ -43,7 +43,7 @@ it 'requires an email' do gatekeeper = described_class.new(FactoryBot.build(:info_request)) - expect{ gatekeeper.allow? }.to raise_error(ArgumentError) + expect { gatekeeper.allow? }.to raise_error(ArgumentError) end it 'allows all emails' do diff --git a/spec/models/info_request/response_gatekeeper/nobody_spec.rb b/spec/models/info_request/response_gatekeeper/nobody_spec.rb index 43dd85ba06..6cd9977867 100644 --- a/spec/models/info_request/response_gatekeeper/nobody_spec.rb +++ b/spec/models/info_request/response_gatekeeper/nobody_spec.rb @@ -11,7 +11,7 @@ describe '.new' do it 'requires an info_request' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'assigns the info_request' do diff --git a/spec/models/info_request/response_gatekeeper_spec.rb b/spec/models/info_request/response_gatekeeper_spec.rb index c57f9c4c0e..e70b1713fc 100644 --- a/spec/models/info_request/response_gatekeeper_spec.rb +++ b/spec/models/info_request/response_gatekeeper_spec.rb @@ -22,7 +22,7 @@ const = 'InfoRequest::ResponseGatekeeper::SPECIALIZED_CLASSES' err = described_class::UnknownResponseGatekeeperError stub_const(const, {}) - expect{ described_class.for('unknown', double('info_request')) }. + expect { described_class.for('unknown', double('info_request')) }. to raise_error(err) end diff --git a/spec/models/info_request/response_rejection/base_spec.rb b/spec/models/info_request/response_rejection/base_spec.rb index daf1789892..edfbbe09d2 100644 --- a/spec/models/info_request/response_rejection/base_spec.rb +++ b/spec/models/info_request/response_rejection/base_spec.rb @@ -6,16 +6,16 @@ describe '.new' do it 'requires an info_request' do - expect{ described_class.new }.to raise_error(ArgumentError) + expect { described_class.new }.to raise_error(ArgumentError) end it 'requires an email' do - expect{ described_class.new(double('info_request')) }. + expect { described_class.new(double('info_request')) }. to raise_error(ArgumentError) end it 'requires a raw_email_data' do - expect{ described_class.new(double('info_request'), double('email')) }. + expect { described_class.new(double('info_request'), double('email')) }. to raise_error(ArgumentError) end diff --git a/spec/models/info_request/response_rejection_spec.rb b/spec/models/info_request/response_rejection_spec.rb index 66d76e063e..d145c3577d 100644 --- a/spec/models/info_request/response_rejection_spec.rb +++ b/spec/models/info_request/response_rejection_spec.rb @@ -24,7 +24,7 @@ stub_const(const, {}) args = [double('info_request'), double('email'), double('raw_email_data')] - expect{ described_class.for('unknown', *args) }. + expect { described_class.for('unknown', *args) }. to raise_error(err) end diff --git a/spec/models/info_request/state/clarification_needed_query_spec.rb b/spec/models/info_request/state/clarification_needed_query_spec.rb index 5b8ab6036a..c56c4b6aa1 100644 --- a/spec/models/info_request/state/clarification_needed_query_spec.rb +++ b/spec/models/info_request/state/clarification_needed_query_spec.rb @@ -4,7 +4,7 @@ describe InfoRequest::State::ClarificationNeededQuery do describe '#call' do - let(:info_request){ FactoryBot.create(:waiting_clarification_info_request) } + let(:info_request) { FactoryBot.create(:waiting_clarification_info_request) } it 'includes those that are waiting for a clarification, and not waiting for description' do diff --git a/spec/models/info_request/state/complete_query_spec.rb b/spec/models/info_request/state/complete_query_spec.rb index 4184c4f12e..c7d793eed0 100644 --- a/spec/models/info_request/state/complete_query_spec.rb +++ b/spec/models/info_request/state/complete_query_spec.rb @@ -4,7 +4,7 @@ describe InfoRequest::State::CompleteQuery do describe '#call' do - let(:info_request){ FactoryBot.create(:successful_request) } + let(:info_request) { FactoryBot.create(:successful_request) } it 'includes those that are successful, and not waiting for description' do diff --git a/spec/models/info_request/state/other_query_spec.rb b/spec/models/info_request/state/other_query_spec.rb index d4b7501b1c..f803c81bda 100644 --- a/spec/models/info_request/state/other_query_spec.rb +++ b/spec/models/info_request/state/other_query_spec.rb @@ -4,7 +4,7 @@ describe InfoRequest::State::OtherQuery do describe '#call' do - let(:info_request){ FactoryBot.create(:info_request_with_internal_review_request) } + let(:info_request) { FactoryBot.create(:info_request_with_internal_review_request) } it 'includes those that are in internal review, and not waiting for description' do diff --git a/spec/models/info_request/state/overdue_query_spec.rb b/spec/models/info_request/state/overdue_query_spec.rb index 27f62dbe78..234a36ef00 100644 --- a/spec/models/info_request/state/overdue_query_spec.rb +++ b/spec/models/info_request/state/overdue_query_spec.rb @@ -8,7 +8,7 @@ it 'includes those that are waiting for a response where the response is past due' do - time_travel_to(Time.zone.parse('2015-10-01')){ info_request } + time_travel_to(Time.zone.parse('2015-10-01')) { info_request } time_travel_to(Time.zone.parse('2015-10-31')) do expect(described_class.new.call.include?(info_request)).to be true end @@ -16,7 +16,7 @@ it 'excludes those that are waiting for a response where the response is very overdue' do - time_travel_to(Time.zone.parse('2015-10-01')){ info_request } + time_travel_to(Time.zone.parse('2015-10-01')) { info_request } time_travel_to(Time.zone.parse('2015-11-30')) do expect(described_class.new.call.include?(info_request)).to be false end diff --git a/spec/models/info_request/state/response_received_query_spec.rb b/spec/models/info_request/state/response_received_query_spec.rb index c3972b5d02..df591d65fc 100644 --- a/spec/models/info_request/state/response_received_query_spec.rb +++ b/spec/models/info_request/state/response_received_query_spec.rb @@ -4,7 +4,7 @@ describe InfoRequest::State::ResponseReceivedQuery do describe '#call' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'includes those that are waiting for description' do info_request.awaiting_description = true diff --git a/spec/models/info_request/state/very_overdue_query_spec.rb b/spec/models/info_request/state/very_overdue_query_spec.rb index 5fb050bf79..2e0fe1ca03 100644 --- a/spec/models/info_request/state/very_overdue_query_spec.rb +++ b/spec/models/info_request/state/very_overdue_query_spec.rb @@ -8,7 +8,7 @@ it 'excludes those that are waiting for a response where the response is past due' do - time_travel_to(Time.zone.parse('2015-10-01')){ info_request } + time_travel_to(Time.zone.parse('2015-10-01')) { info_request } time_travel_to(Time.zone.parse('2015-10-31')) do expect(described_class.new.call.include?(info_request)).to be false end @@ -16,7 +16,7 @@ it 'includes those that are waiting for a response where the response is very overdue' do - time_travel_to(Time.zone.parse('2015-10-01')){ info_request } + time_travel_to(Time.zone.parse('2015-10-01')) { info_request } time_travel_to(Time.zone.parse('2015-11-30')) do expect(described_class.new.call.include?(info_request)).to be true end diff --git a/spec/models/info_request/state_spec.rb b/spec/models/info_request/state_spec.rb index 1ac106025c..074f6d6895 100644 --- a/spec/models/info_request/state_spec.rb +++ b/spec/models/info_request/state_spec.rb @@ -47,7 +47,7 @@ end it 'raises an error for an unknown state' do - expect{ InfoRequest::State.short_description('meow') } + expect { InfoRequest::State.short_description('meow') } .to raise_error 'unknown status meow' end @@ -65,7 +65,7 @@ end it 'raises an error for an unknown state' do - expect{ InfoRequest::State.short_description('meow') } + expect { InfoRequest::State.short_description('meow') } .to raise_error 'unknown status meow' end diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 7a9f8da082..70ac41f123 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -485,7 +485,7 @@ end describe 'receiving mail from different sources' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'processes mail where no source is specified' do email, raw_email = email_and_raw_email @@ -1550,7 +1550,7 @@ end it 'raises an error when given an unknown key' do - expect{ info_request.law_used_human(:random) }.to raise_error. + expect { info_request.law_used_human(:random) }.to raise_error. with_message( "Unknown key 'random' for '#{info_request.law_used}'") end @@ -1573,7 +1573,7 @@ end it 'raises an error when given an unknown key' do - expect{ info_request.law_used_human(:random) }.to raise_error. + expect { info_request.law_used_human(:random) }.to raise_error. with_message( "Unknown key 'random' for '#{info_request.law_used}'") end @@ -1584,22 +1584,22 @@ let(:info_request) { InfoRequest.new(:law_used => 'unknown') } it 'raises an error when asked for law_used_full string' do - expect{ info_request.law_used_human(:full) }.to raise_error. + expect { info_request.law_used_human(:full) }.to raise_error. with_message("Unknown law used '#{info_request.law_used}'") end it 'raises an error when asked for law_used_short string' do - expect{ info_request.law_used_human(:short) }.to raise_error. + expect { info_request.law_used_human(:short) }.to raise_error. with_message("Unknown law used '#{info_request.law_used}'") end it 'raises an error when asked for law_used_act string' do - expect{ info_request.law_used_human(:act) }.to raise_error. + expect { info_request.law_used_human(:act) }.to raise_error. with_message("Unknown law used '#{info_request.law_used}'") end it 'raises an error when given an unknown key' do - expect{ info_request.law_used_human(:random) }.to raise_error. + expect { info_request.law_used_human(:random) }.to raise_error. with_message("Unknown law used '#{info_request.law_used}'") end @@ -2145,7 +2145,7 @@ it "copes with indexing after item is deleted" do load_raw_emails_data - IncomingMessage.find_each{ |message| message.parse_raw_email! } + IncomingMessage.find_each { |message| message.parse_raw_email! } destroy_and_rebuild_xapian_index # delete event from underneath indexing; shouldn't cause error info_request_events(:useless_incoming_message_event).save! @@ -2724,7 +2724,7 @@ def create_old_unclassified_holding_pen describe '#prominence' do - let(:info_request){ FactoryBot.build(:info_request) } + let(:info_request) { FactoryBot.build(:info_request) } it 'returns the prominence of the request' do expect(info_request.prominence).to eq("normal") @@ -3445,7 +3445,7 @@ def create_old_unclassified_holding_pen it 'coalesces duplicate requests' do request_events, request_events_all_successful = InfoRequest.recent_requests - expect(request_events.map(&:info_request).select{|x|x.url_title =~ /^spam/}.length).to eq(1) + expect(request_events.map(&:info_request).select {|x|x.url_title =~ /^spam/}.length).to eq(1) end end @@ -3806,7 +3806,7 @@ def email_and_raw_email(opts = {}) # We want to make the info_request in the past, then effectively # jump forward to a point where it's delayed and we would be calling # log_overdue_events to mark it as overdue - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-30')) do request_summary = info_request.request_summary expect(request_summary.request_summary_categories). @@ -3829,7 +3829,7 @@ def email_and_raw_email(opts = {}) # We want to make the info_request in the past, then effectively # jump forward to a point where it's delayed and we would be calling # log_overdue_events to mark it as overdue - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-02-28')) do request_summary = info_request.request_summary expect(request_summary.request_summary_categories). @@ -4014,7 +4014,7 @@ def email_and_raw_email(opts = {}) describe InfoRequest do describe '#date_initial_request_last_sent_at' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } context 'when there is a value stored in the database' do @@ -4040,7 +4040,7 @@ def email_and_raw_email(opts = {}) end describe '#calculate_date_initial_request_last_sent_at' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'returns a date' do expect(info_request.calculate_date_initial_request_last_sent_at) @@ -4055,7 +4055,7 @@ def email_and_raw_email(opts = {}) end describe '#last_event_forming_initial_request' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } context 'when there is a value in the database' do @@ -4071,7 +4071,7 @@ def email_and_raw_email(opts = {}) it 'raises an error if the request has never been sent' do info_request.send(:write_attribute, :last_event_forming_initial_request_id, InfoRequestEvent.maximum(:id)+1) - expect{ info_request.last_event_forming_initial_request } + expect { info_request.last_event_forming_initial_request } .to raise_error(RuntimeError) end @@ -4096,7 +4096,7 @@ def email_and_raw_email(opts = {}) outgoing_message.record_email_delivery('', '', 'resent') resending_event = info_request. info_request_events.reload. - detect{ |e| e.event_type == 'resent'} + detect { |e| e.event_type == 'resent'} expect(info_request.last_event_forming_initial_request) .to eq resending_event end @@ -4115,14 +4115,14 @@ def email_and_raw_email(opts = {}) outgoing_message.record_email_delivery('', '') followup_event = info_request. info_request_events.reload. - detect{ |e| e.event_type == 'followup_sent'} + detect { |e| e.event_type == 'followup_sent'} expect(info_request.last_event_forming_initial_request) .to eq followup_event end it 'raises an error if the request has never been sent' do info_request.info_request_events.destroy_all - expect{ info_request.last_event_forming_initial_request } + expect { info_request.last_event_forming_initial_request } .to raise_error(RuntimeError) end @@ -4131,7 +4131,7 @@ def email_and_raw_email(opts = {}) end describe '#date_response_required_by' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } context 'when there is a value stored in the database' do @@ -4162,7 +4162,7 @@ def email_and_raw_email(opts = {}) end describe '#calculate_date_response_required_by' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'returns the date a response is required by' do time_travel_to(Time.zone.parse('2014-12-31')) do @@ -4174,7 +4174,7 @@ def email_and_raw_email(opts = {}) end describe '#date_very_overdue_after' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } context 'when there is a value stored in the database' do @@ -4205,7 +4205,7 @@ def email_and_raw_email(opts = {}) end describe '#calculate_date_very_overdue_after' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'returns the date a response is required by' do time_travel_to(Time.zone.parse('2014-12-31')) do @@ -4217,7 +4217,7 @@ def email_and_raw_email(opts = {}) end describe '#log_event' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'creates an event with the type and params passed' do info_request.log_event("resent", :param => 'value') @@ -4240,7 +4240,7 @@ def email_and_raw_email(opts = {}) it 'sets the due dates for the request' do # initial request sent - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-01')) do event = info_request.log_event("resent", :param => 'value') @@ -4290,11 +4290,11 @@ def email_and_raw_email(opts = {}) end describe '#set_due_dates' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } before do # initial request sent - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } # due dates updated based on new event time_travel_to(Time.zone.parse('2015-01-01')) do @event = FactoryBot.create(:sent_event) @@ -4334,7 +4334,7 @@ def email_and_raw_email(opts = {}) context 'when an InfoRequest is not overdue' do it 'does not create an event' do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-15')) do InfoRequest.log_overdue_events overdue_events = info_request. @@ -4350,7 +4350,7 @@ def email_and_raw_email(opts = {}) it "creates an overdue event at the beginning of the first day after the request's due date" do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-30')) do InfoRequest.log_overdue_events @@ -4393,7 +4393,7 @@ def email_and_raw_email(opts = {}) it "creates an overdue event at the beginning of the first day after the request's due date" do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-30')) do InfoRequest.log_overdue_events @@ -4425,7 +4425,7 @@ def email_and_raw_email(opts = {}) describe '.log_very_overdue_events' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } let(:use_notifications_request) do FactoryBot.create(:use_notifications_request) end @@ -4434,7 +4434,7 @@ def email_and_raw_email(opts = {}) it 'should not create an event' do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-01-30')) do InfoRequest.log_very_overdue_events @@ -4450,7 +4450,7 @@ def email_and_raw_email(opts = {}) it "creates an overdue event at the beginning of the first day after the request's date_very_overdue_after" do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-02-28')) do InfoRequest.log_very_overdue_events @@ -4494,7 +4494,7 @@ def email_and_raw_email(opts = {}) it "creates a very_overdue event at the beginning of the first day after the request's date_very_overdue_after" do - time_travel_to(Time.zone.parse('2014-12-31')){ info_request } + time_travel_to(Time.zone.parse('2014-12-31')) { info_request } time_travel_to(Time.zone.parse('2015-02-28')) do InfoRequest.log_very_overdue_events @@ -4527,7 +4527,7 @@ def email_and_raw_email(opts = {}) describe '#last_embargo_set_event' do context 'if no embargo has been set' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'returns nil' do expect(info_request.last_embargo_set_event).to be_nil @@ -4536,8 +4536,8 @@ def email_and_raw_email(opts = {}) end context 'if embargos have been set' do - let(:embargo){ FactoryBot.create(:embargo) } - let(:embargo_extension){ FactoryBot.create(:embargo_extension) } + let(:embargo) { FactoryBot.create(:embargo) } + let(:embargo_extension) { FactoryBot.create(:embargo_extension) } it 'returns the last "set_embargo" event' do last_embargo_set_event = embargo.info_request.last_embargo_set_event diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index 894db6e8df..5586afd498 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -1836,7 +1836,7 @@ it 'should handle a salutation with a bracket in it' do outgoing_message = FactoryBot.build(:initial_request) allow(outgoing_message).to receive(:get_salutation).and_return("Dear Bob (Robert,") - expect{ outgoing_message.valid? }.not_to raise_error + expect { outgoing_message.valid? }.not_to raise_error end end diff --git a/spec/models/pro_account_spec.rb b/spec/models/pro_account_spec.rb index 1606ac58f1..fd34432d7a 100644 --- a/spec/models/pro_account_spec.rb +++ b/spec/models/pro_account_spec.rb @@ -80,7 +80,7 @@ end it 'raises an error' do - expect{ pro_account.stripe_customer }. + expect { pro_account.stripe_customer }. to raise_error Stripe::InvalidRequestError end diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index da15081e7f..f5a826a285 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -1239,7 +1239,7 @@ def set_default_attributes(public_body) it 'should raise an error if there are associated info_requests' do FactoryBot.create(:info_request, :public_body => public_body) public_body.reload - expect{ public_body.destroy }.to raise_error(ActiveRecord::InvalidForeignKey) + expect { public_body.destroy }.to raise_error(ActiveRecord::InvalidForeignKey) end end @@ -1661,7 +1661,7 @@ def set_default_attributes(public_body) # the way categories are loaded every time from the PublicBody class. For now we just # test some translation was done. body = PublicBody.find_by_name('North West Fake Authority') - expect(body.translated_locales.map{|l|l.to_s}.sort).to eq(["en", "es"]) + expect(body.translated_locales.map {|l|l.to_s}.sort).to eq(["en", "es"]) end it "should not fail if a locale is not found in the input file" do @@ -2149,7 +2149,7 @@ def set_default_attributes(public_body) it 'should raise an error if the body is not defunct, FOI applies and has an email address' do expected_error = "not_requestable_reason called with type that has no reason" - expect{ @body.not_requestable_reason }.to raise_error(expected_error) + expect { @body.not_requestable_reason }.to raise_error(expected_error) end end @@ -2264,7 +2264,7 @@ def set_default_attributes(public_body) end describe PublicBody::Version do - let(:public_body){ FactoryBot.create(:public_body) } + let(:public_body) { FactoryBot.create(:public_body) } describe '#compare' do diff --git a/spec/models/raw_email_spec.rb b/spec/models/raw_email_spec.rb index 6d75b3266b..5e2c04bef4 100644 --- a/spec/models/raw_email_spec.rb +++ b/spec/models/raw_email_spec.rb @@ -221,7 +221,7 @@ def test_real(fixture_file, expected) it 'should only delete the directory if it exists' do expect(File).to receive(:delete).once.and_call_original raw_email.destroy_file_representation! - expect{ raw_email.destroy_file_representation! }.not_to raise_error + expect { raw_email.destroy_file_representation! }.not_to raise_error end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 9c803ac861..8bb1a1f103 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1147,37 +1147,37 @@ def create_user(options = {}) end it 'should anonymise user name' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :name).to('[Name Removed] (Account suspended)') end it 'should anonymise user email' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :email).to('1234@invalid') end it 'should anonymise user url_name' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :url_name).to('1234') end it 'should anonymise user about_me' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :about_me).to('') end it 'should anonymise user password' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :password).to('ABCD') end it 'should set user to not receive email alerts' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :receive_email_alerts?).to(false) end it 'should set user to be closed' do - expect{ user.close_and_anonymise }. + expect { user.close_and_anonymise }. to change(user, :closed?).to(true) end @@ -1450,8 +1450,8 @@ def create_user(options = {}) end describe '#can_admin_role?' do - let(:admin_user){ FactoryBot.create(:admin_user) } - let(:pro_user){ FactoryBot.create(:pro_user) } + let(:admin_user) { FactoryBot.create(:admin_user) } + let(:pro_user) { FactoryBot.create(:pro_user) } it 'returns true for an admin user and the admin role' do expect(admin_user.can_admin_role?(:admin)) diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb index 683af4bf70..04e3e2597d 100644 --- a/spec/models/xapian_spec.rb +++ b/spec/models/xapian_spec.rb @@ -387,7 +387,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(0) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map{|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) # only reindex 'tag' and text dropfirst = true terms = "U" @@ -410,7 +410,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(1) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map{|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) # only reindex 'variety' term, blowing away existing data dropfirst = true destroy_and_rebuild_xapian_index(terms, values, texts, dropfirst) @@ -419,7 +419,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(0) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map{|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) end end diff --git a/spec/support/email_helpers.rb b/spec/support/email_helpers.rb index a17e5be24f..ed421c3490 100644 --- a/spec/support/email_helpers.rb +++ b/spec/support/email_helpers.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- def load_raw_emails_data raw_emails_yml = File.join(RSpec.configuration.fixture_path, "raw_emails.yml") - for raw_email_id in YAML::load_file(raw_emails_yml).map{|k,v| v["id"]} do + for raw_email_id in YAML::load_file(raw_emails_yml).map {|k,v| v["id"]} do raw_email = RawEmail.find(raw_email_id) raw_email.data = load_file_fixture("raw_emails/%d.email" % [raw_email_id]) end @@ -19,7 +19,7 @@ def get_fixture_mail(filename, email_to = nil, email_from = nil) end def parse_all_incoming_messages - IncomingMessage.find_each{ |message| message.parse_raw_email! } + IncomingMessage.find_each { |message| message.parse_raw_email! } end def load_mail_server_logs(log) diff --git a/spec/views/admin_public_body/show.html.erb_spec.rb b/spec/views/admin_public_body/show.html.erb_spec.rb index 11ec4c26eb..0a98efe81b 100644 --- a/spec/views/admin_public_body/show.html.erb_spec.rb +++ b/spec/views/admin_public_body/show.html.erb_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe "admin_public_body/show.html.erb" do - let(:public_body){ FactoryBot.create(:public_body) } + let(:public_body) { FactoryBot.create(:public_body) } before do @@ -14,7 +14,7 @@ end context 'when the user cannot view API keys ' do - let(:current_user){ FactoryBot.create(:admin_user) } + let(:current_user) { FactoryBot.create(:admin_user) } it 'does not display the API key' do with_feature_enabled(:alaveteli_pro) do @@ -27,7 +27,7 @@ end context 'when the user can view API keys' do - let(:current_user){ FactoryBot.create(:pro_admin_user) } + let(:current_user) { FactoryBot.create(:pro_admin_user) } it 'displays the API key' do with_feature_enabled(:alaveteli_pro) do diff --git a/spec/views/admin_request/show.html.erb_spec.rb b/spec/views/admin_request/show.html.erb_spec.rb index 064bce0b42..2f64bdf733 100644 --- a/spec/views/admin_request/show.html.erb_spec.rb +++ b/spec/views/admin_request/show.html.erb_spec.rb @@ -8,7 +8,7 @@ end context 'for a public request' do - let(:info_request){ FactoryBot.create(:info_request) } + let(:info_request) { FactoryBot.create(:info_request) } it 'links to the public request page' do render @@ -23,7 +23,7 @@ end context 'for an embargoed request' do - let(:info_request){ FactoryBot.create(:embargoed_request) } + let(:info_request) { FactoryBot.create(:embargoed_request) } it 'links to the pro request page' do render diff --git a/spec/views/admin_user/show.html.erb_spec.rb b/spec/views/admin_user/show.html.erb_spec.rb index e30361b8fd..7cc32499dd 100644 --- a/spec/views/admin_user/show.html.erb_spec.rb +++ b/spec/views/admin_user/show.html.erb_spec.rb @@ -12,8 +12,8 @@ end context 'when the current user cannot login as the user being viewed' do - let(:current_user){ FactoryBot.create(:admin_user) } - let(:user_being_viewed){ FactoryBot.create(:pro_user) } + let(:current_user) { FactoryBot.create(:admin_user) } + let(:user_being_viewed) { FactoryBot.create(:pro_user) } it 'should not show the list of post redirects' do with_feature_enabled(:alaveteli_pro) do @@ -26,8 +26,8 @@ end context 'when the current user can login as the user being viewed' do - let(:current_user){ FactoryBot.create(:pro_admin_user) } - let(:user_being_viewed){ FactoryBot.create(:pro_user) } + let(:current_user) { FactoryBot.create(:pro_admin_user) } + let(:user_being_viewed) { FactoryBot.create(:pro_user) } it 'should show the list of post redirects' do with_feature_enabled(:alaveteli_pro) do From 64e239cbf10e81e8aebee178f94aa26b4c6db5ec Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:13:50 +0100 Subject: [PATCH 009/114] Correct space before semicolon Command: `bundle exec rubocop --only Layout/SpaceBeforeSemicolon --auto-correct` --- app/controllers/alaveteli_pro/stripe_webhooks_controller.rb | 6 +++--- app/controllers/user_profile/about_me_controller.rb | 2 +- app/models/info_request/response_gatekeeper.rb | 2 +- app/models/info_request/response_rejection.rb | 2 +- app/models/public_body.rb | 2 +- spec/models/public_body_spec.rb | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb index a6a8f4ff1c..2dc6deca9b 100644 --- a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb +++ b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb @@ -1,9 +1,9 @@ # -*- encoding : utf-8 -*- # Does not inherit from AlaveteliPro::BaseController because it doesn't need to class AlaveteliPro::StripeWebhooksController < ApplicationController - class UnhandledStripeWebhookError < StandardError ; end - class MissingTypeStripeWebhookError < StandardError ; end - class UnknownPlanStripeWebhookError < StandardError ; end + class UnhandledStripeWebhookError < StandardError; end + class MissingTypeStripeWebhookError < StandardError; end + class UnknownPlanStripeWebhookError < StandardError; end rescue_from JSON::ParserError, MissingTypeStripeWebhookError do |exception| # Invalid payload, reject the webhook diff --git a/app/controllers/user_profile/about_me_controller.rb b/app/controllers/user_profile/about_me_controller.rb index 53d40e0528..74ac55c451 100644 --- a/app/controllers/user_profile/about_me_controller.rb +++ b/app/controllers/user_profile/about_me_controller.rb @@ -3,7 +3,7 @@ class UserProfile::AboutMeController < ApplicationController before_action :set_title before_action :check_user_logged_in - def edit ; end + def edit; end def update if @user.suspended? diff --git a/app/models/info_request/response_gatekeeper.rb b/app/models/info_request/response_gatekeeper.rb index df05cc82e4..6c1f7b5398 100644 --- a/app/models/info_request/response_gatekeeper.rb +++ b/app/models/info_request/response_gatekeeper.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- class InfoRequest module ResponseGatekeeper - class UnknownResponseGatekeeperError < ArgumentError ; end + class UnknownResponseGatekeeperError < ArgumentError; end SPECIALIZED_CLASSES = { 'nobody' => Nobody, 'anybody' => Base, diff --git a/app/models/info_request/response_rejection.rb b/app/models/info_request/response_rejection.rb index 3886b78493..73e9ca46e4 100644 --- a/app/models/info_request/response_rejection.rb +++ b/app/models/info_request/response_rejection.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- class InfoRequest module ResponseRejection - class UnknownResponseRejectionError < ArgumentError ; end + class UnknownResponseRejectionError < ArgumentError; end SPECIALIZED_CLASSES = { 'bounce' => Bounce, 'holding_pen' => HoldingPen, diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 62e8e45fcd..3b2f98d525 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -28,7 +28,7 @@ class PublicBody < ApplicationRecord include AdminColumn - class ImportCSVDryRun < StandardError ; end + class ImportCSVDryRun < StandardError; end @non_admin_columns = %w(name last_edit_comment) diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index f5a826a285..747f45005f 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -52,7 +52,7 @@ it 'update with translated name' do body = FactoryBot.create(:public_body) - AlaveteliLocalization.with_locale(:es) { body.name = 'hola' ; body.save } + AlaveteliLocalization.with_locale(:es) { body.name = 'hola'; body.save } body.reload expect(body.update_attributes('name' => nil)).to eq(false) @@ -82,7 +82,7 @@ it 'blank string update with translated name' do body = FactoryBot.create(:public_body) - AlaveteliLocalization.with_locale(:es) { body.name = 'hola' ; body.save } + AlaveteliLocalization.with_locale(:es) { body.name = 'hola'; body.save } body.reload expect(body.update_attributes('name' => '')).to eq(false) From b2d79781cccb2d3e596647dce6cfdce8e5100329 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:16:04 +0100 Subject: [PATCH 010/114] Correct space inside block braces Command: `bundle exec rubocop --only Layout/SpaceInsideBlockBraces --auto-correct` --- .../admin_incoming_message_controller.rb | 2 +- app/controllers/application_controller.rb | 2 +- app/controllers/public_body_controller.rb | 2 +- app/controllers/request_controller.rb | 2 +- app/controllers/user_controller.rb | 8 ++++---- app/helpers/application_helper.rb | 4 ++-- app/models/alaveteli_pro/request_filter.rb | 6 +++--- app/models/info_request.rb | 4 ++-- app/models/info_request/state.rb | 2 +- app/models/info_request_event.rb | 2 +- app/models/public_body.rb | 4 ++-- config/deploy.rb | 2 +- lib/acts_as_xapian/acts_as_xapian.rb | 18 +++++++++--------- lib/acts_as_xapian/tasks/xapian.rake | 4 ++-- lib/data_export.rb | 2 +- lib/i18n_fixes.rb | 2 +- lib/memory_profiler.rb | 2 +- lib/strip_empty_sessions.rb | 2 +- lib/tasks/reindex.rake | 6 +++--- lib/typeahead_search.rb | 2 +- lib/use_spans_for_errors.rb | 2 +- lib/world_foi_websites.rb | 2 +- ...aft_info_request_batches_controller_spec.rb | 2 +- spec/controllers/api_controller_spec.rb | 2 +- spec/controllers/general_controller_spec.rb | 14 +++++++------- spec/controllers/request_controller_spec.rb | 6 +++--- spec/factories/mail_server_log_dones.rb | 2 +- spec/integration/classify_request_spec.rb | 2 +- spec/lib/graphs_spec.rb | 2 +- spec/lib/mail_handler/mail_handler_spec.rb | 2 +- spec/models/info_request_event_spec.rb | 2 +- spec/models/info_request_spec.rb | 10 +++++----- spec/models/mail_server_log_spec.rb | 2 +- spec/models/notification_spec.rb | 2 +- spec/models/public_body_spec.rb | 2 +- spec/models/xapian_spec.rb | 6 +++--- spec/spec_helper.rb | 2 +- spec/support/email_helpers.rb | 2 +- 38 files changed, 71 insertions(+), 71 deletions(-) diff --git a/app/controllers/admin_incoming_message_controller.rb b/app/controllers/admin_incoming_message_controller.rb index 6652cc34c7..1d60f260f1 100644 --- a/app/controllers/admin_incoming_message_controller.rb +++ b/app/controllers/admin_incoming_message_controller.rb @@ -72,7 +72,7 @@ def bulk_destroy def redeliver - message_ids = params[:url_title].split(",").each {|x| x.strip} + message_ids = params[:url_title].split(",").each { |x| x.strip } previous_request = @incoming_message.info_request destination_request = nil diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f918a3dc6d..0e983fd841 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -223,7 +223,7 @@ def foi_fragment_cache_path(param) max_file_length = 255 - 35 # we subtract 35 because tempfile # adds on a variable number of # characters - return File.join(File.split(path).map {|x| x[0...max_file_length]}) + return File.join(File.split(path).map { |x| x[0...max_file_length] }) end def foi_fragment_cache_exists?(key_path) diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 78a21b8def..bc88a12aea 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -88,7 +88,7 @@ def show :has_json => true } ] respond_to do |format| - format.html { @has_json = true; render :template => "public_body/show"} + format.html { @has_json = true; render :template => "public_body/show" } format.json { render :json => @public_body.json_for_api } end diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index ebf0dd979e..02cbb370ce 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -130,7 +130,7 @@ def show @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] respond_to do |format| - format.html { @has_json = true; render :template => 'request/show'} + format.html { @has_json = true; render :template => 'request/show' } format.json { render :json => @info_request.json_for_api(true) } end end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 68f28355ab..cc572555c4 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -90,8 +90,8 @@ def wall @xapian_comments = nil end - feed_results += @xapian_requests.results.map {|x| x[:model]} if @xapian_requests - feed_results += @xapian_comments.results.map {|x| x[:model]} if @xapian_comments + feed_results += @xapian_requests.results.map { |x| x[:model] } if @xapian_requests + feed_results += @xapian_comments.results.map { |x| x[:model] } if @xapian_comments # All tracks for the user if @is_you @@ -106,7 +106,7 @@ def wall :sort_by_ascending => true, :collapse_by_prefix => nil, :limit => 20) - feed_results += xapian_object.results.map {|x| x[:model]} + feed_results += xapian_object.results.map { |x| x[:model] } end end @@ -136,7 +136,7 @@ def signup if user_alreadyexists # attempt to remove the 'already in use message' from the errors hash # so it doesn't get accidentally shown to the end user - @user_signup.errors[:email].delete_if {|message| message == _("This email is already in use")} + @user_signup.errors[:email].delete_if { |message| message == _("This email is already in use") } end if error || !@user_signup.errors.empty? # Show the form diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fd8c66b4d6..7b98e8a738 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -35,8 +35,8 @@ module ApplicationHelper # Copied from error_messages_for in active_record_helper.rb def foi_error_messages_for(*params) options = params.last.is_a?(Hash) ? params.pop.symbolize_keys : {} - objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact - count = objects.inject(0) {|sum, object| sum + object.errors.count } + objects = params.collect { |object_name| instance_variable_get("@#{object_name}") }.compact + count = objects.inject(0) { |sum, object| sum + object.errors.count } unless count.zero? html = {} [:id, :class].each do |key| diff --git a/app/models/alaveteli_pro/request_filter.rb b/app/models/alaveteli_pro/request_filter.rb index a55846af8b..ad95806684 100644 --- a/app/models/alaveteli_pro/request_filter.rb +++ b/app/models/alaveteli_pro/request_filter.rb @@ -95,7 +95,7 @@ def order_capital_labels end def order_labels - Hash[ order_attributes.map { |atts| [atts[:param], atts[:label]]} ] + Hash[ order_attributes.map { |atts| [atts[:param], atts[:label]] } ] end def order_value @@ -132,7 +132,7 @@ def filter_attributes end def filter_options - filter_attributes.map {|atts| [atts[:capital_label], atts[:param]] } + filter_attributes.map { |atts| [atts[:capital_label], atts[:param]] } end def filter_capital_labels @@ -148,7 +148,7 @@ def filter_values end def filter_labels - Hash[ filter_attributes.map { |atts| [atts[:param], atts[:label]]} ] + Hash[ filter_attributes.map { |atts| [atts[:param], atts[:label]] } ] end def filter_value diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 21d42cb981..653c2f071c 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -614,7 +614,7 @@ def self.recent_requests more_events = xapian_object.results.map { |r| r[:model] } request_events += more_events # Overall we still want the list sorted with the newest first - request_events.sort! {|e1,e2| e2.created_at <=> e1.created_at} + request_events.sort! { |e1,e2| e2.created_at <=> e1.created_at } else request_events_all_successful = true end @@ -1265,7 +1265,7 @@ def get_last_public_response end def public_outgoing_events - info_request_events.select {|e| e.outgoing? && e.outgoing_message.is_public? } + info_request_events.select { |e| e.outgoing? && e.outgoing_message.is_public? } end # The last public outgoing message diff --git a/app/models/info_request/state.rb b/app/models/info_request/state.rb index 3b597f6495..960d2e5c77 100644 --- a/app/models/info_request/state.rb +++ b/app/models/info_request/state.rb @@ -92,7 +92,7 @@ def self.phases end def self.phase_params - Hash[phases.map { |atts| [ atts[:scope], atts[:param] ]}] + Hash[phases.map { |atts| [ atts[:scope], atts[:param] ] }] end end end diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index 27254b1ceb..d946ce0e7f 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -138,7 +138,7 @@ def requested_from # although it relies on a translated field in PublicBody. Hence, we need to # manually add all the localized values to the index (Xapian can handle a list # of values in a term, btw) - info_request.public_body.translations.map {|t| t.url_name} + info_request.public_body.translations.map { |t| t.url_name } end def commented_by diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 3b2f98d525..682a3fd7eb 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -185,7 +185,7 @@ def compare(previous = nil, &block) changes = [] else v = self - changes = self.class.content_columns.inject([]) {|memo, c| + changes = self.class.content_columns.inject([]) { |memo, c| unless %w(version last_edit_editor last_edit_comment @@ -477,7 +477,7 @@ def self.import_csv_from_file(csv_filename, tag, tag_behaviour, dry_run, editor, # Parse the first line as a field list if it starts with '#' if line==1 and row.first.to_s =~ /^#(.*)$/ row[0] = row[0][1..-1] # Remove the # sign on first field - row.each_with_index {|field, i| field_names[field] = i} + row.each_with_index { |field, i| field_names[field] = i } next end diff --git a/config/deploy.rb b/config/deploy.rb index 71bdeebcf1..a1246934ff 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -81,7 +81,7 @@ end # "ln -sf " creates a symbolic link but deletes if it already exists - run links.map {|a| "ln -sf #{a.last} #{a.first}"}.join(";") + run links.map { |a| "ln -sf #{a.last} #{a.first}" }.join(";") end namespace :assets do diff --git a/lib/acts_as_xapian/acts_as_xapian.rb b/lib/acts_as_xapian/acts_as_xapian.rb index e66205add2..dec2b825ef 100644 --- a/lib/acts_as_xapian/acts_as_xapian.rb +++ b/lib/acts_as_xapian/acts_as_xapian.rb @@ -478,7 +478,7 @@ def initialize(model_classes, query_string, options = {}, user_query = nil) self.query_string = query_string # Construct query which only finds things from specified models - model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map {|mc| "M" + mc.to_s}) + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map { |mc| "M" + mc.to_s }) if user_query.nil? user_query = ActsAsXapian.query_parser.parse_query( self.query_string, @@ -559,7 +559,7 @@ def initialize(model_classes, query_models, options = {}) self.query_models = query_models # Find the documents by their unique term - input_models_query = Xapian::Query.new(Xapian::Query::OP_OR, query_models.map {|m| "I" + m.xapian_document_term}) + input_models_query = Xapian::Query.new(Xapian::Query::OP_OR, query_models.map { |m| "I" + m.xapian_document_term }) ActsAsXapian.enquire.query = input_models_query matches = ActsAsXapian.enquire.mset(0, 100, 100) # TODO: so this whole method will only work with 100 docs @@ -589,7 +589,7 @@ def initialize(model_classes, query_models, options = {}) combined_query = Xapian::Query.new(Xapian::Query::OP_AND_NOT, similar_query, input_models_query) # Restrain to model classes - model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map {|mc| "M" + mc.to_s}) + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map { |mc| "M" + mc.to_s }) self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, combined_query) } @@ -901,16 +901,16 @@ def xapian_value(field, type = nil, index_translations = false) value = single_xapian_value(field, type = type) else values = [] - for locale in self.translations.map {|x| x.locale} + for locale in self.translations.map { |x| x.locale } AlaveteliLocalization.with_locale(locale) do values << single_xapian_value(field, type=type) end end if values[0].kind_of?(Array) values = values.flatten - value = values.reject {|x| x.nil?} + value = values.reject { |x| x.nil? } else - values = values.reject {|x| x.nil?} + values = values.reject { |x| x.nil? } value = values.join(" ") end end @@ -936,7 +936,7 @@ def single_xapian_value(field, type = nil) else # Arrays are for terms which require multiple of them, e.g. tags if value.kind_of?(Array) - value.map {|v| v.to_s} + value.map { |v| v.to_s } else value.to_s end @@ -973,7 +973,7 @@ def xapian_index(terms = true, values = true, texts = true) if terms and self.xapian_options[:terms] terms_to_index = self.xapian_options[:terms].dup if terms.is_a?(String) - terms_to_index.reject! {|term| !terms.include?(term[1])} + terms_to_index.reject! { |term| !terms.include?(term[1]) } if terms_to_index.length == self.xapian_options[:terms].length drop_all_terms = true end @@ -999,7 +999,7 @@ def xapian_index(terms = true, values = true, texts = true) doc.add_term("M" + self.class.to_s) doc.add_term("I" + doc.data) else - term_prefixes_to_index = terms_to_index.map {|x| x[1]} + term_prefixes_to_index = terms_to_index.map { |x| x[1] } for existing_term in doc.terms first_letter = existing_term.term[0...1] if !"MI".include?(first_letter) # it's not one of the reserved value diff --git a/lib/acts_as_xapian/tasks/xapian.rake b/lib/acts_as_xapian/tasks/xapian.rake index a01df6b8d0..fee2ccf49d 100644 --- a/lib/acts_as_xapian/tasks/xapian.rake +++ b/lib/acts_as_xapian/tasks/xapian.rake @@ -41,7 +41,7 @@ namespace :xapian do end raise "specify ALL your models with models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? ActsAsXapian.destroy_and_rebuild_index( - ENV['models'].split(" ").map {|m| m.constantize}, + ENV['models'].split(" ").map { |m| m.constantize }, coerce_arg(ENV['verbose'], false), coerce_arg(ENV['terms'], true), coerce_arg(ENV['values'], true), @@ -54,7 +54,7 @@ namespace :xapian do task :query => :environment do raise "specify models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? raise "specify query=\"your terms\" as parameter" if ENV['query'].nil? - s = ActsAsXapian::Search.new(ENV['models'].split(" ").map {|m| m.constantize}, + s = ActsAsXapian::Search.new(ENV['models'].split(" ").map { |m| m.constantize }, ENV['query'], :offset => (ENV['offset'] || 0), :limit => (ENV['limit'] || 10), :sort_by_prefix => (ENV['sort_by_prefix'] || nil), diff --git a/lib/data_export.rb b/lib/data_export.rb index dc86759b8d..b54960b740 100644 --- a/lib/data_export.rb +++ b/lib/data_export.rb @@ -59,7 +59,7 @@ def self.detects_gender(name) end def self.gender_lambda - lambda {|x| detects_gender(x.name)} + lambda { |x| detects_gender(x.name) } end # Remove all instances of user's name (if there is a user), otherwise diff --git a/lib/i18n_fixes.rb b/lib/i18n_fixes.rb index 6e70f44fdf..16e5815e84 100644 --- a/lib/i18n_fixes.rb +++ b/lib/i18n_fixes.rb @@ -52,7 +52,7 @@ def gettext_interpolate(string, values) module GettextI18nRails class Backend def available_locales - FastGettext.available_locales.map {|l| l.to_sym} || [] + FastGettext.available_locales.map { |l| l.to_sym } || [] end end end diff --git a/lib/memory_profiler.rb b/lib/memory_profiler.rb index 41b873ed7c..e9029ff5af 100644 --- a/lib/memory_profiler.rb +++ b/lib/memory_profiler.rb @@ -56,7 +56,7 @@ def self.start(opt={}) end file.puts "Top 20" - delta.sort_by { |k,v| -v.abs }[0..19].sort_by { |k,v| -v}.each do |k,v| + delta.sort_by { |k,v| -v.abs }[0..19].sort_by { |k,v| -v }.each do |k,v| file.printf "%+5d: %s (%d)\n", v, k.name, curr[k] unless v == 0 end file.flush diff --git a/lib/strip_empty_sessions.rb b/lib/strip_empty_sessions.rb index 3d407be524..2fc2cb8a8b 100644 --- a/lib/strip_empty_sessions.rb +++ b/lib/strip_empty_sessions.rb @@ -16,7 +16,7 @@ def call(env) if session_data if (session_data.keys - STRIPPABLE_KEYS).empty? if set_cookie.is_a? Array - set_cookie.reject! {|c| c.match(/^\n?#{@options[:key]}=/)} + set_cookie.reject! { |c| c.match(/^\n?#{@options[:key]}=/) } elsif set_cookie.is_a? String headers[HTTP_SET_COOKIE].gsub!( /(^|\n)#{@options[:key]}=.*?(\n|$)/, "" ) end diff --git a/lib/tasks/reindex.rake b/lib/tasks/reindex.rake index b928f01fba..f34213b3da 100644 --- a/lib/tasks/reindex.rake +++ b/lib/tasks/reindex.rake @@ -27,7 +27,7 @@ namespace :reindex do reindex_log.error("** Error while processing event #{current_id}, " \ "last event successfully queued was: #{last_id}") reindex_log.error("uncaught #{e} exception while handling connection: #{e.message}") - reindex_log.error("Stack trace: #{e.backtrace.map {|l| " #{l}\n"}.join}") + reindex_log.error("Stack trace: #{e.backtrace.map { |l| " #{l}\n" }.join}") abort end end @@ -58,7 +58,7 @@ namespace :reindex do reindex_log.error("** Error while processing body #{current_id}, " \ "last body successfully queued was: #{last_id}") reindex_log.error("uncaught #{e} exception while handling connection: #{e.message}") - reindex_log.error("Stack trace: #{e.backtrace.map {|l| " #{l}\n"}.join}") + reindex_log.error("Stack trace: #{e.backtrace.map { |l| " #{l}\n" }.join}") abort end end @@ -89,7 +89,7 @@ namespace :reindex do reindex_log.error("** Error while processing user #{current_id}, " \ "last user successfully queued was: #{last_id}") reindex_log.error("uncaught #{e} exception while handling connection: #{e.message}") - reindex_log.error("Stack trace: #{e.backtrace.map {|l| " #{l}\n"}.join}") + reindex_log.error("Stack trace: #{e.backtrace.map { |l| " #{l}\n" }.join}") abort end end diff --git a/lib/typeahead_search.rb b/lib/typeahead_search.rb index 6434a3098d..ace5494591 100644 --- a/lib/typeahead_search.rb +++ b/lib/typeahead_search.rb @@ -90,7 +90,7 @@ def prepared_query @query end if @exclude_tags - tag_string = @exclude_tags.map {|tag| "-tag:#{tag}"}.join(" ") + tag_string = @exclude_tags.map { |tag| "-tag:#{tag}" }.join(" ") query = "#{query} #{tag_string}" end query diff --git a/lib/use_spans_for_errors.rb b/lib/use_spans_for_errors.rb index 5da8aec98f..62544d70c3 100644 --- a/lib/use_spans_for_errors.rb +++ b/lib/use_spans_for_errors.rb @@ -9,4 +9,4 @@ # # See http://dev.rubyonrails.org/ticket/2210 -ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| %(#{html_tag}).html_safe} +ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| %(#{html_tag}).html_safe } diff --git a/lib/world_foi_websites.rb b/lib/world_foi_websites.rb index 28f2b6a9d8..b6e5a5a308 100644 --- a/lib/world_foi_websites.rb +++ b/lib/world_foi_websites.rb @@ -140,7 +140,7 @@ def self.world_foi_websites end def self.by_code(code) - result = self.world_foi_websites.find {|x| x[:country_iso_code].downcase == code.downcase} + result = self.world_foi_websites.find { |x| x[:country_iso_code].downcase == code.downcase } return result end diff --git a/spec/controllers/alaveteli_pro/draft_info_request_batches_controller_spec.rb b/spec/controllers/alaveteli_pro/draft_info_request_batches_controller_spec.rb index 83001f715d..f84206f6d6 100644 --- a/spec/controllers/alaveteli_pro/draft_info_request_batches_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/draft_info_request_batches_controller_spec.rb @@ -4,7 +4,7 @@ shared_examples_for "creating a request" do it "creates a new DraftInfoRequestBatch" do expect { subject }. - to change {AlaveteliPro::DraftInfoRequestBatch.count }.by 1 + to change { AlaveteliPro::DraftInfoRequestBatch.count }.by 1 end end diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb index 7675537c62..a6fd1578cf 100644 --- a/spec/controllers/api_controller_spec.rb +++ b/spec/controllers/api_controller_spec.rb @@ -533,7 +533,7 @@ def _create_request assigns[:events].each do |event| expect(event.info_request.public_body).to eq(public_bodies(:geraldine_public_body)) expect(event.outgoing_message).not_to be_nil - expect(event.event_type).to satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)} + expect(event.event_type).to satisfy { |x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x) } end expect(assigns[:event_data].size).to eq(assigns[:events].size) diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb index d39c229c54..64fceb6285 100644 --- a/spec/controllers/general_controller_spec.rb +++ b/spec/controllers/general_controller_spec.rb @@ -308,20 +308,20 @@ it "should filter results based on end of URL being 'all'" do get :search, params: { :combined => "bob/all" } - expect(assigns[:xapian_requests].results.map {|x| x[:model]}).to match_array([ + expect(assigns[:xapian_requests].results.map { |x| x[:model] }).to match_array([ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), info_request_events(:useful_incoming_message_event), info_request_events(:another_useful_incoming_message_event), ]) - expect(assigns[:xapian_users].results.map {|x| x[:model]}).to eq([users(:bob_smith_user)]) + expect(assigns[:xapian_users].results.map { |x| x[:model] }).to eq([users(:bob_smith_user)]) expect(assigns[:xapian_bodies].results).to eq([]) end it "should filter results based on end of URL being 'users'" do get :search, params: { :combined => "bob/users" } expect(assigns[:xapian_requests]).to eq(nil) - expect(assigns[:xapian_users].results.map {|x| x[:model]}).to eq([users(:bob_smith_user)]) + expect(assigns[:xapian_users].results.map { |x| x[:model] }).to eq([users(:bob_smith_user)]) expect(assigns[:xapian_bodies]).to eq(nil) end @@ -338,7 +338,7 @@ it "should filter results based on end of URL being 'requests'" do get :search, params: { :combined => "bob/requests" } - expect(assigns[:xapian_requests].results.map {|x|x[:model]}).to match_array([ + expect(assigns[:xapian_requests].results.map { |x|x[:model] }).to match_array([ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), info_request_events(:useful_incoming_message_event), @@ -352,7 +352,7 @@ get :search, params: { :combined => "quango/bodies" } expect(assigns[:xapian_requests]).to eq(nil) expect(assigns[:xapian_users]).to eq(nil) - expect(assigns[:xapian_bodies].results.map {|x|x[:model]}).to eq([public_bodies(:geraldine_public_body)]) + expect(assigns[:xapian_bodies].results.map { |x|x[:model] }).to eq([public_bodies(:geraldine_public_body)]) end it 'should prioritise direct matches of public body names' do @@ -392,7 +392,7 @@ it "should not show unconfirmed users" do get :search, params: { :combined => "unconfirmed/users" } expect(response).to render_template('search') - expect(assigns[:xapian_users].results.map {|x|x[:model]}).to eq([]) + expect(assigns[:xapian_users].results.map { |x|x[:model] }).to eq([]) end it "should show newly-confirmed users" do @@ -403,7 +403,7 @@ get :search, params: { :combined => "unconfirmed/users" } expect(response).to render_template('search') - expect(assigns[:xapian_users].results.map {|x|x[:model]}).to eq([u]) + expect(assigns[:xapian_users].results.map { |x|x[:model] }).to eq([u]) end it "should show tracking links for requests-only searches" do diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 3dff44960e..71b94b8f9f 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -2112,7 +2112,7 @@ def post_status(status, info_request) describe 'when the request is old and unclassified' do - let(:info_request) { FactoryBot.create(:old_unclassified_request)} + let(:info_request) { FactoryBot.create(:old_unclassified_request) } describe 'when the user is not logged in' do @@ -2744,7 +2744,7 @@ def expect_redirect(status, redirect_path) end context 'when the request is embargoed' do - let(:embargoed_request) { FactoryBot.create(:embargoed_request)} + let(:embargoed_request) { FactoryBot.create(:embargoed_request) } it 'raises an ActiveRecord::RecordNotFound error' do expect { @@ -3302,7 +3302,7 @@ def make_request describe 'GET #details' do - let(:info_request) { FactoryBot.create(:info_request)} + let(:info_request) { FactoryBot.create(:info_request) } it 'renders the details template' do get :details, params: { :url_title => info_request.url_title } diff --git a/spec/factories/mail_server_log_dones.rb b/spec/factories/mail_server_log_dones.rb index 2304232e8d..c64bc0eae0 100644 --- a/spec/factories/mail_server_log_dones.rb +++ b/spec/factories/mail_server_log_dones.rb @@ -13,7 +13,7 @@ FactoryBot.define do factory :mail_server_log_done do - filename { "/var/log/mail/mail.log-#{ Date.current.to_s(:number )} "} + filename { "/var/log/mail/mail.log-#{ Date.current.to_s(:number )} " } last_stat { Time.current } end diff --git a/spec/integration/classify_request_spec.rb b/spec/integration/classify_request_spec.rb index b86e004ad0..27b3f917a7 100644 --- a/spec/integration/classify_request_spec.rb +++ b/spec/integration/classify_request_spec.rb @@ -306,7 +306,7 @@ context 'marking request as waiting_response' do - let(:classification) {'waiting_response1'} + let(:classification) { 'waiting_response1' } it 'displays a thank you message post redirect' do using_session(login(user)) do diff --git a/spec/lib/graphs_spec.rb b/spec/lib/graphs_spec.rb index b252c4d69c..34cf18f390 100644 --- a/spec/lib/graphs_spec.rb +++ b/spec/lib/graphs_spec.rb @@ -34,7 +34,7 @@ it "raises an error if there is a mistake in the SQL statement" do sql = "SELECT * FROM there_is_no_table_here" - expect {dummy_class.select_as_columns(sql)}. + expect { dummy_class.select_as_columns(sql) }. to raise_error(ActiveRecord::StatementInvalid) end diff --git a/spec/lib/mail_handler/mail_handler_spec.rb b/spec/lib/mail_handler/mail_handler_spec.rb index a6ef151614..17457f42ed 100644 --- a/spec/lib/mail_handler/mail_handler_spec.rb +++ b/spec/lib/mail_handler/mail_handler_spec.rb @@ -285,7 +285,7 @@ def expect_content_type(fixture_file, content_type) it 'should correctly return the types in an example bounce report' do mail = get_fixture_mail('track-response-ms-bounce.email') - report = mail.parts.detect { |part| MailHandler.get_content_type(part) == 'multipart/report'} + report = mail.parts.detect { |part| MailHandler.get_content_type(part) == 'multipart/report' } expect(MailHandler.get_content_type(report.parts[0])).to eq('text/plain') expect(MailHandler.get_content_type(report.parts[1])).to eq('message/delivery-status') expect(MailHandler.get_content_type(report.parts[2])).to eq('message/rfc822') diff --git a/spec/models/info_request_event_spec.rb b/spec/models/info_request_event_spec.rb index 210da4b911..829764a71b 100644 --- a/spec/models/info_request_event_spec.rb +++ b/spec/models/info_request_event_spec.rb @@ -498,7 +498,7 @@ end describe '#destroy' do - let (:info_request) { FactoryBot.create(:info_request)} + let (:info_request) { FactoryBot.create(:info_request) } let (:event) { InfoRequestEvent.create(:info_request => info_request, :event_type => 'sent', :params => {}) diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 70ac41f123..40dd6bd5dd 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -1323,7 +1323,7 @@ it 'removes any zip files' do # expire deletes foi_fragment_cache_directories as well as the zip files # so stubbing out the call lets us just see the effect we care about here - allow(info_request).to receive(:foi_fragment_cache_directories) {[]} + allow(info_request).to receive(:foi_fragment_cache_directories) { [] } expect(FileUtils).to receive(:rm_rf).with(info_request.download_zip_dir) info_request.expire end @@ -2335,7 +2335,7 @@ end it "rejects invalid states" do - expect {@ir.set_described_state("foo")}.to raise_error(ActiveRecord::RecordInvalid) + expect { @ir.set_described_state("foo") }.to raise_error(ActiveRecord::RecordInvalid) end it "accepts core states" do @@ -3445,7 +3445,7 @@ def create_old_unclassified_holding_pen it 'coalesces duplicate requests' do request_events, request_events_all_successful = InfoRequest.recent_requests - expect(request_events.map(&:info_request).select {|x|x.url_title =~ /^spam/}.length).to eq(1) + expect(request_events.map(&:info_request).select { |x|x.url_title =~ /^spam/ }.length).to eq(1) end end @@ -4096,7 +4096,7 @@ def email_and_raw_email(opts = {}) outgoing_message.record_email_delivery('', '', 'resent') resending_event = info_request. info_request_events.reload. - detect { |e| e.event_type == 'resent'} + detect { |e| e.event_type == 'resent' } expect(info_request.last_event_forming_initial_request) .to eq resending_event end @@ -4115,7 +4115,7 @@ def email_and_raw_email(opts = {}) outgoing_message.record_email_delivery('', '') followup_event = info_request. info_request_events.reload. - detect { |e| e.event_type == 'followup_sent'} + detect { |e| e.event_type == 'followup_sent' } expect(info_request.last_event_forming_initial_request) .to eq followup_event end diff --git a/spec/models/mail_server_log_spec.rb b/spec/models/mail_server_log_spec.rb index 72791d0c87..e489d003eb 100644 --- a/spec/models/mail_server_log_spec.rb +++ b/spec/models/mail_server_log_spec.rb @@ -208,7 +208,7 @@ end context "Postfix" do - let(:log) {[ + let(:log) { [ "Oct 3 16:39:35 host postfix/pickup[2257]: CB55836EE58C: uid=1003 from=", "Oct 3 16:39:35 host postfix/cleanup[7674]: CB55836EE58C: message-id=", "Oct 3 16:39:35 host postfix/qmgr[1673]: 9634B16F7F7: from=, size=368, nrcpt=1 (queue active)", diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 633ac51722..90e8d01048 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -108,7 +108,7 @@ FactoryBot.create(:notification, info_request_event: embargo_expiring_event) end - let(:notifications) { [notification, expired_notification]} + let(:notifications) { [notification, expired_notification] } context "when no notifications are expired" do it "returns the original list" do diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index 747f45005f..9d6317d9ef 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -1661,7 +1661,7 @@ def set_default_attributes(public_body) # the way categories are loaded every time from the PublicBody class. For now we just # test some translation was done. body = PublicBody.find_by_name('North West Fake Authority') - expect(body.translated_locales.map {|l|l.to_s}.sort).to eq(["en", "es"]) + expect(body.translated_locales.map { |l|l.to_s }.sort).to eq(["en", "es"]) end it "should not fail if a locale is not found in the input file" do diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb index 04e3e2597d..1c9a76f732 100644 --- a/spec/models/xapian_spec.rb +++ b/spec/models/xapian_spec.rb @@ -387,7 +387,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(0) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map { |x|x[:model] }).to match_array(PublicBody.all) # only reindex 'tag' and text dropfirst = true terms = "U" @@ -410,7 +410,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(1) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map { |x|x[:model] }).to match_array(PublicBody.all) # only reindex 'variety' term, blowing away existing data dropfirst = true destroy_and_rebuild_xapian_index(terms, values, texts, dropfirst) @@ -419,7 +419,7 @@ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) expect(xapian_object.results.size).to eq(0) xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) - expect(xapian_object.results.map {|x|x[:model]}).to match_array(PublicBody.all) + expect(xapian_object.results.map { |x|x[:model] }).to match_array(PublicBody.all) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4969e3c571..7ae5cf2921 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,7 +30,7 @@ # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. -Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} +Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } load "#{Rails.root}/db/seeds.rb" # Use test-specific translations diff --git a/spec/support/email_helpers.rb b/spec/support/email_helpers.rb index ed421c3490..1a816a888b 100644 --- a/spec/support/email_helpers.rb +++ b/spec/support/email_helpers.rb @@ -1,7 +1,7 @@ # -*- encoding : utf-8 -*- def load_raw_emails_data raw_emails_yml = File.join(RSpec.configuration.fixture_path, "raw_emails.yml") - for raw_email_id in YAML::load_file(raw_emails_yml).map {|k,v| v["id"]} do + for raw_email_id in YAML::load_file(raw_emails_yml).map { |k,v| v["id"] } do raw_email = RawEmail.find(raw_email_id) raw_email.data = load_file_fixture("raw_emails/%d.email" % [raw_email_id]) end From 87a74bdfb04bc76115db4088e3cef88a7cb318ee Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:24:18 +0100 Subject: [PATCH 011/114] Exclude Gemfile from indentation consistency cop Without this IndentationConsistency catches how we represent gems which are dependencies of dependencies. --- .ruby-style.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ruby-style.yml b/.ruby-style.yml index b778c0c849..eaa5bc1a8b 100644 --- a/.ruby-style.yml +++ b/.ruby-style.yml @@ -126,6 +126,8 @@ Layout/FirstParameterIndentation: Layout/IndentationConsistency: Description: 'Keep indentation straight.' Enabled: true + Exclude: + - Gemfile Layout/IndentationWidth: Description: 'Use 2 spaces for indentation.' From ee0c9272a62b982cd0e6a38a87a276d8b1ab6bae Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Tue, 25 Jun 2019 10:25:03 +0100 Subject: [PATCH 012/114] Exclude commonlib from Rubocop Any Rubocop errors/warnings should be fixed within the parent repo. --- .ruby-style.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ruby-style.yml b/.ruby-style.yml index eaa5bc1a8b..dca10aeadb 100644 --- a/.ruby-style.yml +++ b/.ruby-style.yml @@ -13,6 +13,7 @@ AllCops: - '**/Rakefile' - '**/Vagrantfile' Exclude: + - 'commonlib/**/*' - 'db/schema.rb' - 'node_modules/**/*' - 'vendor/**/*' From 7238d2a6fbaa670f88aabfdbc7763bb57228eecb Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Mon, 1 Jul 2019 10:07:57 +0100 Subject: [PATCH 013/114] Update changelog --- doc/CHANGES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 6472ad0264..4f6b9e72b6 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -1,3 +1,10 @@ +# develop + +## Highlighted Features + +* Fixed bug where expiring embargoes were not fully removed from batches when + the related requests reached the publication data (Liz Conlan) + # 0.34.0.0 ## Highlighted Features From 862961d3ef2a12b9c7e6b663c4323b1aec818a57 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 17:17:43 +0100 Subject: [PATCH 014/114] Don't ignore subscription renewals webhooks Instead of raising exceptions we're going to be email a digest of events generated from unhandled webhook notifications. This will be useful information to include. --- .../alaveteli_pro/stripe_webhooks_controller.rb | 13 ------------- .../stripe_webhooks_controller_spec.rb | 5 +++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb index 2dc6deca9b..b2acd39437 100644 --- a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb +++ b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb @@ -35,8 +35,6 @@ class UnknownPlanStripeWebhookError < StandardError; end def receive case @stripe_event.type - when 'customer.subscription.updated' - customer_subscription_updated when 'customer.subscription.deleted' customer_subscription_deleted when 'invoice.payment_succeeded' @@ -54,17 +52,6 @@ def receive private - def customer_subscription_updated - unless renewal?(@stripe_event.data[:previous_attributes]) - raise UnhandledStripeWebhookError.new(@stripe_event.type) - end - end - - def renewal?(previous_attributes) - previous_attributes.keys.to_set == - %i(current_period_start current_period_end latest_invoice).to_set - end - def customer_subscription_deleted account = pro_account_from_stripe_event(@stripe_event) account.user.remove_role(:pro) if account diff --git a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb index 14430c69d0..24dee815c9 100644 --- a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb @@ -306,8 +306,9 @@ def send_request expect(response.status).to eq(200) end - it 'does not sent an exception email' do - expect(ActionMailer::Base.deliveries).to be_empty + it 'sends an exception email' do + mail = ActionMailer::Base.deliveries.first + expect(mail.subject).to match(/UnhandledStripeWebhookError/) end end From 337ee7a33ae6b891aa88a4e9e1a62a899b46d687 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 17:22:33 +0100 Subject: [PATCH 015/114] Add Webhook model So we can store Webhooks in the database so the infomation within can be emailed in a digest instead individually as they are received. --- app/models/webhook.rb | 9 +++++++++ db/migrate/20190626153909_create_webhooks.rb | 10 ++++++++++ spec/factories/webhooks.rb | 6 ++++++ spec/models/webhook_spec.rb | 14 ++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 app/models/webhook.rb create mode 100644 db/migrate/20190626153909_create_webhooks.rb create mode 100644 spec/factories/webhooks.rb create mode 100644 spec/models/webhook_spec.rb diff --git a/app/models/webhook.rb b/app/models/webhook.rb new file mode 100644 index 0000000000..38aaefaf81 --- /dev/null +++ b/app/models/webhook.rb @@ -0,0 +1,9 @@ +## +# A class which represents a Webhook from a 3rd party service or integration. +# +# Currently the only service which is sending webhooks is Stripe as part of Pro +# pricing. +# +class Webhook < ApplicationRecord + validates :params, presence: true +end diff --git a/db/migrate/20190626153909_create_webhooks.rb b/db/migrate/20190626153909_create_webhooks.rb new file mode 100644 index 0000000000..35b6319d25 --- /dev/null +++ b/db/migrate/20190626153909_create_webhooks.rb @@ -0,0 +1,10 @@ +class CreateWebhooks < ActiveRecord::Migration[5.0] + def change + create_table :webhooks do |t| + t.jsonb :params + t.datetime :notified_at + + t.timestamps + end + end +end diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb new file mode 100644 index 0000000000..ed0b469ebd --- /dev/null +++ b/spec/factories/webhooks.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :webhook do + params('type' => 'payment') + notified_at nil + end +end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb new file mode 100644 index 0000000000..4da3c298f6 --- /dev/null +++ b/spec/models/webhook_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +RSpec.describe Webhook, type: :model do + let(:webhook) { FactoryBot.build(:webhook) } + + describe 'validations' do + specify { expect(webhook).to be_valid } + + it 'requires params' do + webhook.params = nil + expect(webhook).not_to be_valid + end + end +end From 91a9c420d36d6da3a98e8affd0b8f9c475160066 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 17:23:13 +0100 Subject: [PATCH 016/114] Remove UnhandledStripeWebhookError exception Instead of raising we now store the Webhooks. To be included in a daily digest email. --- .../stripe_webhooks_controller.rb | 14 +++--- .../stripe_webhooks_controller_spec.rb | 43 ++++++------------- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb index b2acd39437..105a552f15 100644 --- a/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb +++ b/app/controllers/alaveteli_pro/stripe_webhooks_controller.rb @@ -1,7 +1,6 @@ # -*- encoding : utf-8 -*- # Does not inherit from AlaveteliPro::BaseController because it doesn't need to class AlaveteliPro::StripeWebhooksController < ApplicationController - class UnhandledStripeWebhookError < StandardError; end class MissingTypeStripeWebhookError < StandardError; end class UnknownPlanStripeWebhookError < StandardError; end @@ -24,13 +23,6 @@ class UnknownPlanStripeWebhookError < StandardError; end status: 200 end - rescue_from UnhandledStripeWebhookError do |exception| - # accept it so it doesn't get resent but notify us that we haven't handled - # it yet. - notify_exception(exception) - render json: { message: 'OK' }, status: 200 - end - before_action :read_event_notification, :check_for_event_type, :filter_hooks def receive @@ -42,7 +34,7 @@ def receive when 'invoice.payment_failed' invoice_payment_failed else - raise UnhandledStripeWebhookError.new(@stripe_event.type) + store_unhandled_webhook end # send a 200 ok to acknowlege receipt of the webhook @@ -81,6 +73,10 @@ def invoice_payment_failed end end + def store_unhandled_webhook + Webhook.create(params: @stripe_event.to_h) + end + def read_event_notification payload = request.body.read sig_header = request.headers['HTTP_STRIPE_SIGNATURE'] diff --git a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb index 24dee815c9..5dadc02f46 100644 --- a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb @@ -139,10 +139,8 @@ def send_request stripe_event.type = 'custom.unhandle_event' end - it 'sends an exception email' do - send_request - mail = ActionMailer::Base.deliveries.first - expect(mail.subject).to match(/UnhandledStripeWebhookError/) + it 'stores unhandled webhook' do + expect { send_request }.to change(Webhook, :count).by(1) end end @@ -212,9 +210,8 @@ def send_request to match('Does not appear to be one of our plans') end - it 'does not send an exception email' do - send_request - expect(ActionMailer::Base.deliveries.count).to eq(0) + it 'does not store unhandled webhook' do + expect { send_request }.to_not change(Webhook, :count) end end @@ -298,17 +295,13 @@ def send_request StripeMock.mock_webhook_event('customer.subscription.updated-renewed') end - before do - send_request - end - it 'handles the event' do + send_request expect(response.status).to eq(200) end - it 'sends an exception email' do - mail = ActionMailer::Base.deliveries.first - expect(mail.subject).to match(/UnhandledStripeWebhookError/) + it 'stores unhandled webhook' do + expect { send_request }.to change(Webhook, :count).by(1) end end @@ -317,36 +310,28 @@ def send_request StripeMock.mock_webhook_event('customer.subscription.updated-trial-end') end - before do - send_request - end - it 'handles the event' do + send_request expect(response.status).to eq(200) end - it 'sends an exception email' do - mail = ActionMailer::Base.deliveries.first - expect(mail.subject).to match(/UnhandledStripeWebhookError/) + it 'stores unhandled webhook' do + expect { send_request }.to change(Webhook, :count).by(1) end end - describe 'a customer cancells' do + describe 'a customer cancels' do let(:stripe_event) do StripeMock.mock_webhook_event('customer.subscription.updated-cancelled') end - before do - send_request - end - it 'handles the event' do + send_request expect(response.status).to eq(200) end - it 'sends an exception email' do - mail = ActionMailer::Base.deliveries.first - expect(mail.subject).to match(/UnhandledStripeWebhookError/) + it 'stores unhandled webhook' do + expect { send_request }.to change(Webhook, :count).by(1) end end From f1e67c0204f9cd1f6da116c0a80be78eeed220c2 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 21:37:46 +0100 Subject: [PATCH 017/114] New Webhook fixtures Based on real webhooks we've received. These have been sanitised to remove any real IDs or codes. --- .../stripe_webhooks_controller_spec.rb | 6 +- .../stripe_webhooks/coupon-code-applied.json | 250 +++++++++++++++++ .../stripe_webhooks/coupon-code-revoked.json | 252 +++++++++++++++++ .../customer.subscription.deleted.json | 35 --- ...stomer.subscription.updated-cancelled.json | 71 ----- ...customer.subscription.updated-renewed.json | 72 ----- ...stomer.subscription.updated-trial-end.json | 72 ----- .../stripe_webhooks/plan-changed.json | 254 +++++++++++++++++ .../subscription-cancelled.json | 168 +++++++++++ .../subscription-reactivated.json | 178 ++++++++++++ .../subscription-renewal-failure.json | 196 +++++++++++++ ...subscription-renewal-repeated-failure.json | 206 ++++++++++++++ .../subscription-renewed-after-failure.json | 200 ++++++++++++++ .../stripe_webhooks/subscription-renewed.json | 166 +++++++++++ .../stripe_webhooks/trial-cancelled.json | 260 ++++++++++++++++++ .../trial-ended-first-payment-failed.json | 256 +++++++++++++++++ .../stripe_webhooks/trial-extended.json | 170 ++++++++++++ 17 files changed, 2559 insertions(+), 253 deletions(-) create mode 100644 spec/fixtures/stripe_webhooks/coupon-code-applied.json create mode 100644 spec/fixtures/stripe_webhooks/coupon-code-revoked.json delete mode 100644 spec/fixtures/stripe_webhooks/customer.subscription.deleted.json delete mode 100644 spec/fixtures/stripe_webhooks/customer.subscription.updated-cancelled.json delete mode 100644 spec/fixtures/stripe_webhooks/customer.subscription.updated-renewed.json delete mode 100644 spec/fixtures/stripe_webhooks/customer.subscription.updated-trial-end.json create mode 100644 spec/fixtures/stripe_webhooks/plan-changed.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-cancelled.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-reactivated.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-renewal-failure.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-renewal-repeated-failure.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-renewed-after-failure.json create mode 100644 spec/fixtures/stripe_webhooks/subscription-renewed.json create mode 100644 spec/fixtures/stripe_webhooks/trial-cancelled.json create mode 100644 spec/fixtures/stripe_webhooks/trial-ended-first-payment-failed.json create mode 100644 spec/fixtures/stripe_webhooks/trial-extended.json diff --git a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb index 5dadc02f46..e3c912d3fb 100644 --- a/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/stripe_webhooks_controller_spec.rb @@ -292,7 +292,7 @@ def send_request describe 'a customer moves to a new billing period' do let(:stripe_event) do - StripeMock.mock_webhook_event('customer.subscription.updated-renewed') + StripeMock.mock_webhook_event('subscription-renewed') end it 'handles the event' do @@ -307,7 +307,7 @@ def send_request describe 'a trial ends' do let(:stripe_event) do - StripeMock.mock_webhook_event('customer.subscription.updated-trial-end') + StripeMock.mock_webhook_event('trial-ended-first-payment-failed') end it 'handles the event' do @@ -322,7 +322,7 @@ def send_request describe 'a customer cancels' do let(:stripe_event) do - StripeMock.mock_webhook_event('customer.subscription.updated-cancelled') + StripeMock.mock_webhook_event('subscription-cancelled') end it 'handles the event' do diff --git a/spec/fixtures/stripe_webhooks/coupon-code-applied.json b/spec/fixtures/stripe_webhooks/coupon-code-applied.json new file mode 100644 index 0000000000..c086ff7d45 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/coupon-code-applied.json @@ -0,0 +1,250 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1531807868, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1537433042, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511882257, + "current_period_end": 1537433042, + "current_period_start": 1511882257, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1531807803, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 100, + "redeem_by": null, + "times_redeemed": 1, + "valid": true + }, + "customer": "cus_123", + "end": null, + "start": 1531807868, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511882258, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1511882257, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1537433042, + "trial_start": 1511882257 + }, + "previous_attributes": { + "discount": null + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1531807868, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1537433042, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511882257, + "current_period_end": 1537433042, + "current_period_start": 1511882257, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1531807803, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 100, + "redeem_by": null, + "times_redeemed": 1, + "valid": true + }, + "customer": "cus_123", + "end": null, + "start": 1531807868, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511882258, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1511882257, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1537433042, + "trial_start": 1511882257 + }, + "previous_attributes": { + "discount": null + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/coupon-code-revoked.json b/spec/fixtures/stripe_webhooks/coupon-code-revoked.json new file mode 100644 index 0000000000..dba4380df0 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/coupon-code-revoked.json @@ -0,0 +1,252 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533112644, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1531814693, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511882257, + "current_period_end": 1534493093, + "current_period_start": 1531814693, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511882258, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1531814693, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1531807803, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 100, + "percent_off_precise": 100.0, + "redeem_by": null, + "times_redeemed": 11, + "valid": true + }, + "customer": "cus_123", + "end": null, + "start": 1531807868, + "subscription": "sub_123" + } + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533112644, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1531814693, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511882257, + "current_period_end": 1534493093, + "current_period_start": 1531814693, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511882258, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1531814693, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1531807803, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 100, + "percent_off_precise": 100.0, + "redeem_by": null, + "times_redeemed": 11, + "valid": true + }, + "customer": "cus_123", + "end": null, + "start": 1531807868, + "subscription": "sub_123" + } + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/customer.subscription.deleted.json b/spec/fixtures/stripe_webhooks/customer.subscription.deleted.json deleted file mode 100644 index f44fa1ac55..0000000000 --- a/spec/fixtures/stripe_webhooks/customer.subscription.deleted.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "id": "evt_00000000000000", - "object": "event", - "type": "customer.subscription.deleted", - "created": 1512658329, - "data": { - "object": { - "id": "su_00000000000000", - "object": "subscription", - "status": "canceled", - "customer": "cus_007", - "items": { - "object": "list", - "data": [{ - "id": "si_00000000000000", - "object": "subscription_item", - "created": 1497881783, - "plan": { - "interval": "month", - "name": "Test", - "amount": 10, - "currency": "gbp", - "id": "fkx0AFo_00000000000000", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": {} - }, - "quantity": 1 - }] - } - } - } -} diff --git a/spec/fixtures/stripe_webhooks/customer.subscription.updated-cancelled.json b/spec/fixtures/stripe_webhooks/customer.subscription.updated-cancelled.json deleted file mode 100644 index 772a65c0db..0000000000 --- a/spec/fixtures/stripe_webhooks/customer.subscription.updated-cancelled.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "id": "evt_00000000000000", - "object": "event", - "type": "customer.subscription.updated", - "created": 1540215500, - "data": { - "object": { - "id": "su_00000000000000", - "items": { - "object": "list", - "data": [ - { - "id": "si_00000000000000", - "object": "subscription_item", - "created": 1497881783, - "plan": { - "id": "fkx0AFo_00000000000000", - "interval": "month", - "name": "Member's Club", - "amount": 100, - "currency": "usd", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 1 - }, - { - "id": "si_00000000000001", - "object": "subscription_item", - "created": 1497881788, - "plan": { - "id": "fkx0AFo_00000000000001", - "interval": "month", - "name": "Vistor's Club", - "amount": 200, - "currency": "eur", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 5 - } - ] - }, - "object": "subscription", - "start": 1381080561, - "status": "active", - "customer": "cus_00000000000000", - "cancel_at_period_end": false, - "current_period_start": 1381080561, - "current_period_end": 1383758961, - "ended_at": null, - "trial_start": null, - "trial_end": null, - "canceled_at": null, - "quantity": 1, - "application_fee_percent": null - }, - "previous_attributes": { - "cancel_at_period_end": false, - "canceled_at": null - } - } -} diff --git a/spec/fixtures/stripe_webhooks/customer.subscription.updated-renewed.json b/spec/fixtures/stripe_webhooks/customer.subscription.updated-renewed.json deleted file mode 100644 index 2c77d69f7a..0000000000 --- a/spec/fixtures/stripe_webhooks/customer.subscription.updated-renewed.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "evt_00000000000000", - "object": "event", - "type": "customer.subscription.updated", - "created": 1540215500, - "data": { - "object": { - "id": "su_00000000000000", - "items": { - "object": "list", - "data": [ - { - "id": "si_00000000000000", - "object": "subscription_item", - "created": 1497881783, - "plan": { - "id": "fkx0AFo_00000000000000", - "interval": "month", - "name": "Member's Club", - "amount": 100, - "currency": "usd", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 1 - }, - { - "id": "si_00000000000001", - "object": "subscription_item", - "created": 1497881788, - "plan": { - "id": "fkx0AFo_00000000000001", - "interval": "month", - "name": "Vistor's Club", - "amount": 200, - "currency": "eur", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 5 - } - ] - }, - "object": "subscription", - "start": 1381080561, - "status": "active", - "customer": "cus_00000000000000", - "cancel_at_period_end": false, - "current_period_start": 1381080561, - "current_period_end": 1383758961, - "ended_at": null, - "trial_start": null, - "trial_end": null, - "canceled_at": null, - "quantity": 1, - "application_fee_percent": null - }, - "previous_attributes": { - "current_period_start": 1378488561, - "current_period_end": 1381076961, - "latest_invoice": "in_1234" - } - } -} diff --git a/spec/fixtures/stripe_webhooks/customer.subscription.updated-trial-end.json b/spec/fixtures/stripe_webhooks/customer.subscription.updated-trial-end.json deleted file mode 100644 index 8a5045a8c2..0000000000 --- a/spec/fixtures/stripe_webhooks/customer.subscription.updated-trial-end.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "evt_00000000000000", - "object": "event", - "type": "customer.subscription.updated", - "created": 1540215500, - "data": { - "object": { - "id": "su_00000000000000", - "items": { - "object": "list", - "data": [ - { - "id": "si_00000000000000", - "object": "subscription_item", - "created": 1497881783, - "plan": { - "id": "fkx0AFo_00000000000000", - "interval": "month", - "name": "Member's Club", - "amount": 100, - "currency": "usd", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 1 - }, - { - "id": "si_00000000000001", - "object": "subscription_item", - "created": 1497881788, - "plan": { - "id": "fkx0AFo_00000000000001", - "interval": "month", - "name": "Vistor's Club", - "amount": 200, - "currency": "eur", - "object": "plan", - "livemode": false, - "interval_count": 1, - "trial_period_days": null, - "metadata": { - } - }, - "quantity": 5 - } - ] - }, - "object": "subscription", - "start": 1381080561, - "status": "active", - "customer": "cus_00000000000000", - "cancel_at_period_end": false, - "current_period_start": 1381080561, - "current_period_end": 1383758961, - "ended_at": null, - "trial_start": null, - "trial_end": null, - "canceled_at": null, - "quantity": 1, - "application_fee_percent": null - }, - "previous_attributes": { - "current_period_start": 1378488561, - "current_period_end": 1381076961, - "status": "trialing" - } - } -} diff --git a/spec/fixtures/stripe_webhooks/plan-changed.json b/spec/fixtures/stripe_webhooks/plan-changed.json new file mode 100644 index 0000000000..233c1c6d7d --- /dev/null +++ b/spec/fixtures/stripe_webhooks/plan-changed.json @@ -0,0 +1,254 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1534859120, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1535446800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884457, + "current_period_end": 1535446800, + "current_period_start": 1534859120, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1534859120, + "metadata": {}, + "plan": { + "id": "pro-annual-billing", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 8333, + "billing_scheme": "per_unit", + "created": 1517835271, + "currency": "gbp", + "interval": "year", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro Annual Billing", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro-annual-billing", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 8333, + "billing_scheme": "per_unit", + "created": 1517835271, + "currency": "gbp", + "interval": "year", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro Annual Billing", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1534859120, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1535446800, + "trial_start": 1511884457 + }, + "previous_attributes": { + "current_period_start": 1511884457, + "items": { + "data": [ + { + "id": "si_123", + "created": 1511884457, + "plan": { + "id": "pro", + "amount": 833, + "created": 1511536024, + "interval": "month", + "name": "Pro", + "product": "prod_123" + } + } + ] + }, + "plan": { + "id": "pro", + "amount": 833, + "created": 1511536024, + "interval": "month", + "name": "Pro", + "product": "prod_123" + }, + "start": 1534756846 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1534859120, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1535446800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884457, + "current_period_end": 1535446800, + "current_period_start": 1534859120, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1534859120, + "metadata": {}, + "plan": { + "id": "pro-annual-billing", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 8333, + "billing_scheme": "per_unit", + "created": 1517835271, + "currency": "gbp", + "interval": "year", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro Annual Billing", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro-annual-billing", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 8333, + "billing_scheme": "per_unit", + "created": 1517835271, + "currency": "gbp", + "interval": "year", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro Annual Billing", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1534859120, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1535446800, + "trial_start": 1511884457 + }, + "previous_attributes": { + "current_period_start": 1511884457, + "items": { + "data": [ + { + "id": "si_123", + "created": 1511884457, + "plan": { + "id": "pro", + "amount": 833, + "created": 1511536024, + "interval": "month", + "name": "Pro", + "product": "prod_123" + } + } + ] + }, + "plan": { + "id": "pro", + "amount": 833, + "created": 1511536024, + "interval": "month", + "name": "Pro", + "product": "prod_123" + }, + "start": 1534756846 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-cancelled.json b/spec/fixtures/stripe_webhooks/subscription-cancelled.json new file mode 100644 index 0000000000..604c65f9f4 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-cancelled.json @@ -0,0 +1,168 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1517839007, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": true, + "canceled_at": 1517839007, + "created": 1512468959, + "current_period_end": 1520244959, + "current_period_start": 1517825759, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1512468960, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1512468959, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "cancel_at_period_end": false, + "canceled_at": null + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1517839007, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": true, + "canceled_at": 1517839007, + "created": 1512468959, + "current_period_end": 1520244959, + "current_period_start": 1517825759, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1512468960, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1512468959, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "cancel_at_period_end": false, + "canceled_at": null + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-reactivated.json b/spec/fixtures/stripe_webhooks/subscription-reactivated.json new file mode 100644 index 0000000000..2d7cea7d55 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-reactivated.json @@ -0,0 +1,178 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1520267708, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1513600201, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1513600201, + "current_period_end": 1521376201, + "current_period_start": 1518957001, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1513600202, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "nickname": null, + "product": "prod_123", + "trial_period_days": null, + "statement_descriptor": null, + "name": "Pro" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "nickname": null, + "product": "prod_123", + "trial_period_days": null, + "statement_descriptor": null, + "name": "Pro" + }, + "quantity": 1, + "start": 1513600201, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "cancel_at_period_end": true, + "canceled_at": 1519317815 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1520267708, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1513600201, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1513600201, + "current_period_end": 1521376201, + "current_period_start": 1518957001, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1513600202, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "nickname": null, + "product": "prod_123", + "trial_period_days": null, + "statement_descriptor": null, + "name": "Pro" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "nickname": null, + "product": "prod_123", + "trial_period_days": null, + "statement_descriptor": null, + "name": "Pro" + }, + "quantity": 1, + "start": 1513600201, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "cancel_at_period_end": true, + "canceled_at": 1519317815 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-renewal-failure.json b/spec/fixtures/stripe_webhooks/subscription-renewal-failure.json new file mode 100644 index 0000000000..ed7f43320f --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-renewal-failure.json @@ -0,0 +1,196 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1524833563, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1522151423, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1522151423, + "current_period_end": 1527421823, + "current_period_start": 1524829823, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1522151424, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1522151423, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "status": "active" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1524833563, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1522151423, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1522151423, + "current_period_end": 1527421823, + "current_period_start": 1524829823, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1522151424, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1522151423, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "status": "active" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-renewal-repeated-failure.json b/spec/fixtures/stripe_webhooks/subscription-renewal-repeated-failure.json new file mode 100644 index 0000000000..116cc89e8d --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-renewal-repeated-failure.json @@ -0,0 +1,206 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1529075593, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1516029146, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1516029146, + "current_period_end": 1531667546, + "current_period_start": 1529075546, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1516029147, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1516029146, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "current_period_end": 1529075546, + "current_period_start": 1526397146 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1529075593, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1516029146, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1516029146, + "current_period_end": 1531667546, + "current_period_start": 1529075546, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1516029147, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1516029146, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "current_period_end": 1529075546, + "current_period_start": 1526397146 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-renewed-after-failure.json b/spec/fixtures/stripe_webhooks/subscription-renewed-after-failure.json new file mode 100644 index 0000000000..4ae79e73a7 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-renewed-after-failure.json @@ -0,0 +1,200 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1525352316, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1522151423, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1522151423, + "current_period_end": 1527421823, + "current_period_start": 1524829823, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1522151424, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1522151423, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "status": "past_due" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1525352316, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1522151423, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1522151423, + "current_period_end": 1527421823, + "current_period_start": 1524829823, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1522151424, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1522151423, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "status": "past_due" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/subscription-renewed.json b/spec/fixtures/stripe_webhooks/subscription-renewed.json new file mode 100644 index 0000000000..35e7c8f5bd --- /dev/null +++ b/spec/fixtures/stripe_webhooks/subscription-renewed.json @@ -0,0 +1,166 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1515147483, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1512468959, + "current_period_end": 1517825759, + "current_period_start": 1515147359, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1512468960, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1 + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1512468959, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "current_period_end": 1515147359, + "current_period_start": 1512468959 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1515147483, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1512468959, + "current_period_end": 1517825759, + "current_period_start": 1515147359, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1512468960, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1 + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1512468959, + "status": "active", + "tax_percent": 20.0, + "trial_end": null, + "trial_start": null + }, + "previous_attributes": { + "current_period_end": 1515147359, + "current_period_start": 1512468959 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/trial-cancelled.json b/spec/fixtures/stripe_webhooks/trial-cancelled.json new file mode 100644 index 0000000000..818bb2e988 --- /dev/null +++ b/spec/fixtures/stripe_webhooks/trial-cancelled.json @@ -0,0 +1,260 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533118637, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1533718800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884283, + "current_period_end": 1533718800, + "current_period_start": 1511884283, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1533118610, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 25, + "percent_off_precise": 25.0, + "redeem_by": null, + "times_redeemed": 1, + "valid": true + }, + "customer": "cus_123", + "end": 1541067437, + "start": 1533118637, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884284, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1533118637, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1533718800, + "trial_start": 1511884283 + }, + "previous_attributes": { + "billing_cycle_anchor": 1546214400, + "current_period_end": 1546214400, + "discount": null, + "start": 1532614135, + "trial_end": 1546214400 + } + }, + "livemode": true, + "pending_webhooks": 1, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533118637, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1533718800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884283, + "current_period_end": 1533718800, + "current_period_start": 1511884283, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1533118610, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 25, + "percent_off_precise": 25.0, + "redeem_by": null, + "times_redeemed": 1, + "valid": true + }, + "customer": "cus_123", + "end": 1541067437, + "start": 1533118637, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884284, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1533118637, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1533718800, + "trial_start": 1511884283 + }, + "previous_attributes": { + "billing_cycle_anchor": 1546214400, + "current_period_end": 1546214400, + "discount": null, + "start": 1532614135, + "trial_end": 1546214400 + } + }, + "livemode": true, + "pending_webhooks": 1, + "request": "req_123", + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/trial-ended-first-payment-failed.json b/spec/fixtures/stripe_webhooks/trial-ended-first-payment-failed.json new file mode 100644 index 0000000000..064bb5c52f --- /dev/null +++ b/spec/fixtures/stripe_webhooks/trial-ended-first-payment-failed.json @@ -0,0 +1,256 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533718988, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1533718800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884203, + "current_period_end": 1536397200, + "current_period_start": 1533718800, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1533118610, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 25, + "percent_off_precise": 25.0, + "redeem_by": null, + "times_redeemed": 12, + "valid": true + }, + "customer": "cus_123", + "end": 1541067448, + "start": 1533118648, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884203, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1533118648, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": 1533718800, + "trial_start": 1511884203 + }, + "previous_attributes": { + "current_period_end": 1533718800, + "current_period_start": 1525077962, + "status": "trialing" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1533718988, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1533718800, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884203, + "current_period_end": 1536397200, + "current_period_start": 1533718800, + "customer": "cus_123", + "days_until_due": null, + "discount": { + "object": "discount", + "coupon": { + "id": "COUPON-123", + "object": "coupon", + "amount_off": null, + "created": 1533118610, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": true, + "max_redemptions": null, + "metadata": {}, + "name": "COUPON-123", + "percent_off": 25, + "percent_off_precise": 25.0, + "redeem_by": null, + "times_redeemed": 12, + "valid": true + }, + "customer": "cus_123", + "end": 1541067448, + "start": 1533118648, + "subscription": "sub_123" + }, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884203, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 833, + "billing_scheme": "per_unit", + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "nickname": null, + "product": "prod_123", + "statement_descriptor": null, + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "start": 1533118648, + "status": "past_due", + "tax_percent": 20.0, + "trial_end": 1533718800, + "trial_start": 1511884203 + }, + "previous_attributes": { + "current_period_end": 1533718800, + "current_period_start": 1525077962, + "status": "trialing" + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": null, + "type": "customer.subscription.updated" + } +} diff --git a/spec/fixtures/stripe_webhooks/trial-extended.json b/spec/fixtures/stripe_webhooks/trial-extended.json new file mode 100644 index 0000000000..24a810c8ea --- /dev/null +++ b/spec/fixtures/stripe_webhooks/trial-extended.json @@ -0,0 +1,170 @@ +{ + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1517317961, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884095, + "current_period_end": 1519862400, + "current_period_start": 1511884095, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884095, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1517317961, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1519862400, + "trial_start": 1511884095 + }, + "previous_attributes": { + "current_period_end": 1519304305, + "start": 1511884095, + "trial_end": 1519304305 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated", + "controller": "alaveteli_pro/stripe_webhooks", + "action": "receive", + "stripe_webhook": { + "id": "evt_123", + "object": "event", + "api_version": "2017-01-27", + "created": 1517317961, + "data": { + "object": { + "id": "sub_123", + "object": "subscription", + "application_fee_percent": null, + "billing": "charge_automatically", + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1511884095, + "current_period_end": 1519862400, + "current_period_start": 1511884095, + "customer": "cus_123", + "days_until_due": null, + "discount": null, + "ended_at": null, + "items": { + "object": "list", + "data": [ + { + "id": "si_123", + "object": "subscription_item", + "created": 1511884095, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "subscription": "sub_123" + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_123" + }, + "livemode": true, + "metadata": {}, + "plan": { + "id": "pro", + "object": "plan", + "amount": 833, + "created": 1511536024, + "currency": "gbp", + "interval": "month", + "interval_count": 1, + "livemode": true, + "metadata": {}, + "name": "Pro", + "statement_descriptor": null, + "trial_period_days": null + }, + "quantity": 1, + "start": 1517317961, + "status": "trialing", + "tax_percent": 20.0, + "trial_end": 1519862400, + "trial_start": 1511884095 + }, + "previous_attributes": { + "current_period_end": 1519304305, + "start": 1511884095, + "trial_end": 1519304305 + } + }, + "livemode": true, + "pending_webhooks": 2, + "request": "req_123", + "type": "customer.subscription.updated" + } +} From 848379b6b55afb8f371e66a8a0fc9bdcec1580eb Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 22:01:00 +0100 Subject: [PATCH 018/114] Configure mail previews This makes it super easy to preview an email template from the browser by visiting /rails/mailers. --- config/environments/development.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/environments/development.rb b/config/environments/development.rb index d533648583..71aabee3cd 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -32,6 +32,10 @@ config.action_mailer.perform_caching = false + config.action_mailer.preview_path = Rails.root.join( + 'spec', 'mailers', 'previews' + ) + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log From 79d7fabe6de3eeec5da1ee6481b3aa9de76b04df Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 22:02:04 +0100 Subject: [PATCH 019/114] Add Webhook digest emails We're stubbing the Webhhok#state for now but eventually we will be parsing the parameters to determine the correct state. --- app/mailers/alaveteli_pro/webhook_mailer.rb | 28 ++++++++++++ app/models/webhook.rb | 18 ++++++++ .../webhook_mailer/digest.text.erb | 6 +++ spec/factories/webhooks.rb | 28 ++++++++++++ .../alaveteli_pro/webhook_mailer_spec.rb | 43 +++++++++++++++++++ .../alaveteli_pro/webhook_mailer_preview.rb | 17 ++++++++ spec/models/webhook_spec.rb | 35 +++++++++++++++ 7 files changed, 175 insertions(+) create mode 100644 app/mailers/alaveteli_pro/webhook_mailer.rb create mode 100644 app/views/alaveteli_pro/webhook_mailer/digest.text.erb create mode 100644 spec/mailers/alaveteli_pro/webhook_mailer_spec.rb create mode 100644 spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb diff --git a/app/mailers/alaveteli_pro/webhook_mailer.rb b/app/mailers/alaveteli_pro/webhook_mailer.rb new file mode 100644 index 0000000000..3e33b72c2b --- /dev/null +++ b/app/mailers/alaveteli_pro/webhook_mailer.rb @@ -0,0 +1,28 @@ +module AlaveteliPro + ## + # A mailer responsible for sending out webhook information to the Pro contact + # + class WebhookMailer < ApplicationMailer + def digest(webhooks) + @customer_webhooks = webhooks.sort_by(&:date).group_by(&:customer_id) + + set_auto_generated_headers + + subject = _( + "{{pro_site_name}} webhook daily digest", + pro_site_name: AlaveteliConfiguration.pro_site_name.html_safe + ) + mail_pro_team(subject) + end + + private + + def mail_pro_team(subject) + mail( + from: pro_contact_from_name_and_email, + to: pro_contact_from_name_and_email, + subject: subject + ) + end + end +end diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 38aaefaf81..9c9a2a81c8 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -6,4 +6,22 @@ # class Webhook < ApplicationRecord validates :params, presence: true + + def date + Time.at(params['created']) if params['created'] + end + + def customer_id + object['customer'] + end + + def state + # fixme + end + + private + + def object + params.dig('data', 'object') || {} + end end diff --git a/app/views/alaveteli_pro/webhook_mailer/digest.text.erb b/app/views/alaveteli_pro/webhook_mailer/digest.text.erb new file mode 100644 index 0000000000..77d342600f --- /dev/null +++ b/app/views/alaveteli_pro/webhook_mailer/digest.text.erb @@ -0,0 +1,6 @@ +<%- @customer_webhooks.each do |customer, webhooks| %> +* https://dashboard.stripe.com/customers/<%= customer %> +<%- webhooks.each do |webhook| %> + - <%= webhook.state %> +<% end %> +<% end %> diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb index ed0b469ebd..7ebadff8de 100644 --- a/spec/factories/webhooks.rb +++ b/spec/factories/webhooks.rb @@ -2,5 +2,33 @@ factory :webhook do params('type' => 'payment') notified_at nil + + transient do + fixture { nil } + created { nil } + customer { nil } + end + + after(:build) do |webhook, evaluator| + next unless evaluator.fixture + + path = Rails.root.join('spec', 'fixtures', 'stripe_webhooks', + evaluator.fixture + '.json') + webhook.params = JSON.parse(File.read(path)).to_h + end + + after(:build) do |webhook, evaluator| + next unless evaluator.created + + webhook.params['created'] = evaluator.created + end + + after(:build) do |webhook, evaluator| + next unless evaluator.customer + + webhook.params['data'] ||= {} + webhook.params['data']['object'] ||= {} + webhook.params['data']['object']['customer'] = evaluator.customer + end end end diff --git a/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb new file mode 100644 index 0000000000..b36d11ec45 --- /dev/null +++ b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +RSpec.describe AlaveteliPro::WebhookMailer do + MockWebhook = Struct.new(:date, :customer_id, :state) + + describe '#digest' do + let(:webhooks) do + [ + MockWebhook.new(Time.new(2019, 01, 02), 'cus_123', 'state_b'), + MockWebhook.new(Time.new(2019, 01, 01), 'cus_123', 'state_a'), + MockWebhook.new(Time.new(2019, 01, 01), 'cus_456', 'state_a') + ] + end + + let(:message) do + AlaveteliPro::WebhookMailer.digest(webhooks).message + end + + it 'sends the email to the pro contact address' do + expect(message.to).to eq [AlaveteliConfiguration.pro_contact_email] + end + + it 'sends the email from the pro contact address' do + expect(message.from).to eq [AlaveteliConfiguration.pro_contact_email] + end + + it 'has a subject including "account request"' do + expect(message.subject).to match('webhook daily digest') + end + + it 'includes a list of webhooks by customers and sorted by date' do + expect(message.body).to include( + <<~TXT + * https://dashboard.stripe.com/customers/cus_123 + - state_a + - state_b + * https://dashboard.stripe.com/customers/cus_456 + - state_a + TXT + ) + end + end +end diff --git a/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb b/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb new file mode 100644 index 0000000000..4ea4eb5dce --- /dev/null +++ b/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb @@ -0,0 +1,17 @@ +module AlaveteliPro + class WebhookMailerPreview < ActionMailer::Preview + def digest + webhooks = [] + + customers = %w(cus_123 cus_456 cus_789) + + 10.times do |idx| + webhooks << FactoryBot.build(:webhook, + created: idx, + customer: customers.sample) + end + + WebhookMailer.digest(webhooks) + end + end +end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index 4da3c298f6..7866d9b51c 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -11,4 +11,39 @@ expect(webhook).not_to be_valid end end + + describe '#date' do + it 'returns nil if there is not a created parameter' do + webhook.params = { 'created' => nil } + expect(webhook.date).to be_nil + end + + it 'returns created parameter and typecast as Time' do + time = Time.now.utc.change(usec: 0) + webhook.params = { 'created' => time.to_i } + expect(webhook.date).to eq time + end + end + + describe '#customer_id' do + it 'returns nil if there is not a data parameter' do + webhook.params = { 'data' => nil } + expect(webhook.date).to be_nil + end + + it 'returns nil if there is not a data.object parameter' do + webhook.params = { 'data' => { 'object' => nil } } + expect(webhook.date).to be_nil + end + + it 'returns nil if there is not a data.object.customer parameter' do + webhook.params = { 'data' => { 'object' => { 'customer' => nil } } } + expect(webhook.date).to be_nil + end + + it 'returns data.object.customer parameter' do + webhook.params = { 'data' => { 'object' => { 'customer' => 'cus_123' } } } + expect(webhook.customer_id).to eq 'cus_123' + end + end end From 6e1f4136495b97dd557866f92c3fa061ec44aa25 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Thu, 27 Jun 2019 09:26:00 +0100 Subject: [PATCH 020/114] Webhook state calculation This has been heavily tested manually to workout the correct states for the unknown webhooks which we've so far received. I've attempted to write the conditionals in a way which wan't break but can never be sure the webhook parameters will remain consistent and/or other webhooks would be mis-categorised. --- app/models/webhook.rb | 66 ++++++++++++++++++++++++++++++++++- spec/factories/webhooks.rb | 2 +- spec/models/webhook_spec.rb | 69 +++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 9c9a2a81c8..bf9b568f89 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -16,12 +16,76 @@ def customer_id end def state - # fixme + subscription_state || renewal_state || trial_state || coupon_state || + plan_state || _('Unknown webhook ({{id}})', id: params['id']) end private + def subscription_state + if previous['canceled_at'].nil? && object['canceled_at'] + _('Subscription cancelled') + elsif previous['canceled_at'] && object['canceled_at'].nil? + _('Subscription reactivated') + end + end + + def renewal_state + if previous['current_period_end'] && object['current_period_start'] && + object['status'] == 'active' + _('Subscription renewed') + elsif previous['status'] == 'active' && object['status'] == 'past_due' + _('Subscription renewal failure') + elsif previous['current_period_end'] && object['current_period_start'] && + previous['status'].nil? && object['status'] == 'past_due' + _('Subscription renewal repeated failure') + elsif previous['status'] == 'past_due' && object['status'] == 'active' + _('Subscription renewed after failure') + end + end + + def trial_state + if previous['trial_end'] && object['trial_end'] && + previous['trial_end'] < object['trial_end'] && + object['status'] == 'trialing' + _('Trial extended') + elsif previous['trial_end'] && object['trial_end'] && + previous['trial_end'] > object['trial_end'] && + object['status'] == 'trialing' + _('Trial cancelled') + elsif previous['status'] == 'trialing' && object['status'] == 'active' + _('Trial ended, first payment succeeded') + elsif previous['status'] == 'trialing' && object['status'] == 'past_due' + _('Trial ended, first payment failed') + end + end + + def coupon_state + if previous['discount'].nil? && object['discount'] + _('Coupon code "{{code}}" applied', + code: object['discount']['coupon']['id'] + ) + elsif previous['discount'] && object['discount'].nil? + _('Coupon code "{{code}}" revoked', + code: previous['discount']['coupon']['id'] + ) + end + end + + def plan_state + if previous['plan'] && previous['plan'] != object['plan'] + _('Plan changed from "{{from}}" to "{{to}}"', + from: previous['plan']['name'], + to: object['plan']['name'] + ) + end + end + def object params.dig('data', 'object') || {} end + + def previous + params.dig('data', 'previous_attributes') || {} + end end diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb index 7ebadff8de..f8cb8fc1e6 100644 --- a/spec/factories/webhooks.rb +++ b/spec/factories/webhooks.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :webhook do - params('type' => 'payment') + params('type' => 'payment', 'id' => 'evt_123') notified_at nil transient do diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index 7866d9b51c..ed4bf7eb20 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -46,4 +46,73 @@ expect(webhook.customer_id).to eq 'cus_123' end end + + describe '#state' do + subject { webhook.state } + + let(:fixture) { nil } + let(:webhook) { FactoryBot.build(:webhook, fixture: fixture) } + + it { is_expected.to eq 'Unknown webhook (evt_123)' } + + context 'coupon-code-applied' do + let(:fixture) { 'coupon-code-applied' } + it { is_expected.to eq 'Coupon code "COUPON-123" applied' } + end + + context 'coupon-code-revoked' do + let(:fixture) { 'coupon-code-revoked' } + it { is_expected.to eq 'Coupon code "COUPON-123" revoked' } + end + + context 'plan-changed' do + let(:fixture) { 'plan-changed' } + it { is_expected.to eq 'Plan changed from "Pro" to "Pro Annual Billing"' } + end + + context 'subscription-cancelled' do + let(:fixture) { 'subscription-cancelled' } + it { is_expected.to eq 'Subscription cancelled' } + end + + context 'subscription-reactivated' do + let(:fixture) { 'subscription-reactivated' } + it { is_expected.to eq 'Subscription reactivated' } + end + + context 'subscription-renewal-failure' do + let(:fixture) { 'subscription-renewal-failure' } + it { is_expected.to eq 'Subscription renewal failure' } + end + + context 'subscription-renewal-repeated-failure' do + let(:fixture) { 'subscription-renewal-repeated-failure' } + it { is_expected.to eq 'Subscription renewal repeated failure' } + end + + context 'subscription-renewed-after-failure' do + let(:fixture) { 'subscription-renewed-after-failure' } + it { is_expected.to eq 'Subscription renewed after failure' } + end + + context 'subscription-renewed' do + let(:fixture) { 'subscription-renewed' } + it { is_expected.to eq 'Subscription renewed' } + end + + context 'trial-cancelled' do + let(:fixture) { 'trial-cancelled' } + it { is_expected.to eq 'Trial cancelled' } + end + + context 'trial-ended-first-payment-failed' do + let(:fixture) { 'trial-ended-first-payment-failed' } + it { is_expected.to eq 'Trial ended, first payment failed' } + end + + context 'trial-extended' do + let(:fixture) { 'trial-extended' } + it { is_expected.to eq 'Trial extended' } + end + end end From 1a9a7dc3474534b556a95aefbc7b9cb98c7ca049 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Thu, 27 Jun 2019 09:26:00 +0100 Subject: [PATCH 021/114] Use Webhook fixtures on digest preview Better and more actuate previews are good. --- .../alaveteli_pro/webhook_mailer_preview.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb b/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb index 4ea4eb5dce..6ad5309b17 100644 --- a/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb +++ b/spec/mailers/previews/alaveteli_pro/webhook_mailer_preview.rb @@ -5,10 +5,26 @@ def digest customers = %w(cus_123 cus_456 cus_789) + fixtures = %w( + coupon-code-applied + coupon-code-revoked + plan-changed + subscription-cancelled + subscription-reactivated + subscription-renewal-failure + subscription-renewal-repeated-failure + subscription-renewed-after-failure + subscription-renewed + trial-cancelled + trial-ended-first-payment-failed + trial-extended + ) + 10.times do |idx| webhooks << FactoryBot.build(:webhook, created: idx, - customer: customers.sample) + customer: customers.sample, + fixture: fixtures.sample) end WebhookMailer.digest(webhooks) From 094a88e4ef6cfd1148ab49533f388789c1455443 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 22:02:39 +0100 Subject: [PATCH 022/114] Add Webhook.pending_notification scope This scope will be used to work out which webhooks will be included on the daily digest. --- app/models/webhook.rb | 2 ++ spec/models/webhook_spec.rb | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/app/models/webhook.rb b/app/models/webhook.rb index bf9b568f89..a5369fc447 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -7,6 +7,8 @@ class Webhook < ApplicationRecord validates :params, presence: true + scope :pending_notification, -> { where(notified_at: nil) } + def date Time.at(params['created']) if params['created'] end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index ed4bf7eb20..839560c0bc 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -12,6 +12,20 @@ end end + describe '.pending_notification' do + subject { Webhook.pending_notification } + + it 'includes webhooks if notified_at is nil' do + webhook = FactoryBot.create(:webhook, notified_at: nil) + is_expected.to include webhook + end + + it 'excludes webhooks if notified_at is set' do + webhook = FactoryBot.create(:webhook, notified_at: Time.zone.now) + is_expected.to_not include webhook + end + end + describe '#date' do it 'returns nil if there is not a created parameter' do webhook.params = { 'created' => nil } From def4aa0bc3dcad62441aae83e03d4e0c1c2310d2 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 26 Jun 2019 22:02:39 +0100 Subject: [PATCH 023/114] Send digest emails daily Once sent update the Webhook#notified_at attribute to remove them from the next digest email. --- app/mailers/alaveteli_pro/webhook_mailer.rb | 10 ++++++ config/crontab-example | 1 + script/send-webhook-digest | 4 +++ .../alaveteli_pro/webhook_mailer_spec.rb | 34 +++++++++++++++++++ spec/support/shared_examples_for_mailers.rb | 9 +++++ 5 files changed, 58 insertions(+) create mode 100755 script/send-webhook-digest create mode 100644 spec/support/shared_examples_for_mailers.rb diff --git a/app/mailers/alaveteli_pro/webhook_mailer.rb b/app/mailers/alaveteli_pro/webhook_mailer.rb index 3e33b72c2b..8906c8ef26 100644 --- a/app/mailers/alaveteli_pro/webhook_mailer.rb +++ b/app/mailers/alaveteli_pro/webhook_mailer.rb @@ -3,6 +3,16 @@ module AlaveteliPro # A mailer responsible for sending out webhook information to the Pro contact # class WebhookMailer < ApplicationMailer + def self.send_digest + return unless feature_enabled?(:pro_pricing) + + webhooks = Webhook.pending_notification + return if webhooks.empty? + + digest(webhooks).deliver_now + webhooks.update_all(notified_at: Time.zone.now) + end + def digest(webhooks) @customer_webhooks = webhooks.sort_by(&:date).group_by(&:customer_id) diff --git a/config/crontab-example b/config/crontab-example index a15fe4d436..cdfb2ae0d5 100644 --- a/config/crontab-example +++ b/config/crontab-example @@ -34,6 +34,7 @@ MAILTO=!!(*= $mailto *)!! 2 4 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/check-recent-requests-sent.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/check-recent-requests-sent || echo "stalled?" 45 3 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/stop-new-responses-on-old-requests.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/stop-new-responses-on-old-requests || echo "stalled?" 55 4 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/update-public-body-stats.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/update-public-body-stats || echo "stalled?" +0 6 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/send-webhook-digest.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/send-webhook-digest || echo "stalled?" # Once a day on all servers 43 2 * * * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/request-creation-graph diff --git a/script/send-webhook-digest b/script/send-webhook-digest new file mode 100755 index 0000000000..7927ecf60b --- /dev/null +++ b/script/send-webhook-digest @@ -0,0 +1,4 @@ +#!/bin/bash +TOP_DIR="$(dirname "$BASH_SOURCE")/.." +cd "$TOP_DIR" +bundle exec rails runner 'AlaveteliPro::WebhookMailer.send_digest' diff --git a/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb index b36d11ec45..013046852e 100644 --- a/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb @@ -3,6 +3,40 @@ RSpec.describe AlaveteliPro::WebhookMailer do MockWebhook = Struct.new(:date, :customer_id, :state) + describe '.send_digest' do + subject { described_class.send_digest } + + let!(:webhook) { FactoryBot.create(:webhook, notified_at: nil) } + + context 'pro pricing enabled', feature: %i[pro_pricing] do + context 'with pending notifications' do + it 'should deliver digest email' do + expect { subject }.to( + change(ActionMailer::Base.deliveries, :size).by(1) + ) + end + + it 'should mark webhook as not pending' do + expect { subject }.to( + change(Webhook.pending_notification, :count).by(-1) + ) + end + end + + context 'without pending notifications' do + before do + allow(Webhook).to receive(:pending_notification).and_return([]) + end + + include_examples 'does not deliver any mail' + end + end + + context 'pro pricing disabled' do + include_examples 'does not deliver any mail' + end + end + describe '#digest' do let(:webhooks) do [ diff --git a/spec/support/shared_examples_for_mailers.rb b/spec/support/shared_examples_for_mailers.rb new file mode 100644 index 0000000000..a2e460e3fb --- /dev/null +++ b/spec/support/shared_examples_for_mailers.rb @@ -0,0 +1,9 @@ +require 'spec_helper' + +RSpec.shared_examples 'does not deliver any mail' do + it { is_expected.to be_nil } + + it 'should not deliver any mail' do + expect { subject }.to_not change(ActionMailer::Base.deliveries, :size) + end +end From 92e65a3c49efd8ecc5a8db7119c1018aa3a9d4a2 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Mon, 1 Jul 2019 12:11:08 +0100 Subject: [PATCH 024/114] Add upgrade note for PostgreSQL requirement --- doc/CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 4f6b9e72b6..98988d6661 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -5,6 +5,11 @@ * Fixed bug where expiring embargoes were not fully removed from batches when the related requests reached the publication data (Liz Conlan) +## Upgrade Notes + +* We no longer support PostgreSQL 9.3 or earlier. Please upgrade to 9.4 or above + before upgrading Alaveteli. See: https://www.postgresql.org/docs/9.4/release-9-4.html + # 0.34.0.0 ## Highlighted Features From be7ea1b1dc4030ede176a8f9b199134642c655d4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 1 Jul 2019 09:06:06 +0100 Subject: [PATCH 025/114] Prevent null bytes in attachment filename While debugging a request I found: attrs[:filename] # => "Tender Loving Care Trust (Europe).pdf\u0000" We've made a fix to the problem in the attachment body in f18c5b9. This commit deletes null bytes from the filename attribute. The deletion of the null bytes must happen before the extension calculation, otherwise the spec fails with: expected: "Tender Loving Care Trust (Europe).pdf" got: "Tender Loving Care Trust (Europe).pdf.pdf" We need a `try` as sometimes the filename being assigned is `nil` and calculated by `FoiAttachment#ensure_filename!`. I didn't think a spec was worth adding here, as the behaviour is covered by the `ensure_filename!` spec In 6c8490b we attributed a similar problem to Tnef. I'm not sure of the cause of the error in this case. Fixes https://github.com/mysociety/alaveteli/issues/5209. --- app/models/foi_attachment.rb | 1 + spec/models/foi_attachment_spec.rb | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index 5324d4bddb..048f8a0005 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -233,6 +233,7 @@ def ensure_filename! end def filename=(filename) + filename.try(:delete!, "\0") calc_ext = AlaveteliFileTypes.mimetype_to_extension(self.content_type) # Put right extension on if missing if !filename.nil? && !filename.match(/\.#{calc_ext}$/) && calc_ext diff --git a/spec/models/foi_attachment_spec.rb b/spec/models/foi_attachment_spec.rb index a74b33f293..4ecdc2600e 100644 --- a/spec/models/foi_attachment_spec.rb +++ b/spec/models/foi_attachment_spec.rb @@ -125,6 +125,13 @@ end + describe '#filename=' do + it 'strips null bytes' do + attachment = FactoryBot.build(:pdf_attachment) + attachment.filename = "Tender Loving Care Trust (Europe).pdf\u0000" + expect(attachment.filename).to eq('Tender Loving Care Trust (Europe).pdf') + end + end describe '#ensure_filename!' do From 07ed21389cccfa1b75a8cbb3dad2bf6a5c051844 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Thu, 28 Feb 2019 12:26:17 +1300 Subject: [PATCH 026/114] Handle failures in ActionMailer that may raise exceptions Adapt new request and followup flows to catch exceptions derived from ActionMailer's deliver_now call. On failure, record the failure as a new OutgoingMessage status "failed". Delivery status information on requests will show messages in the "failed" status as undelivered despite no mail logs, and allow admins to resend failed messages. Avoids unintended Denial-of-Service of Agency and/or Administrative pages. Additionally, fix follow-up messages not getting the outgoing message ID. --- app/controllers/followups_controller.rb | 35 +++++++++++++-------- app/controllers/request_controller.rb | 36 ++++++++++++++-------- app/models/info_request.rb | 6 +++- app/models/info_request_event.rb | 3 +- app/models/outgoing_message.rb | 29 ++++++++++++++--- app/views/request/_correspondence.html.erb | 2 +- 6 files changed, 80 insertions(+), 31 deletions(-) diff --git a/app/controllers/followups_controller.rb b/app/controllers/followups_controller.rb index 4df5a7eab2..60f16c9cc5 100644 --- a/app/controllers/followups_controller.rb +++ b/app/controllers/followups_controller.rb @@ -139,20 +139,31 @@ def outgoing_message_params def send_followup @outgoing_message.sendable? - mail_message = OutgoingMailer.followup( - @outgoing_message.info_request, - @outgoing_message, - @outgoing_message.incoming_message_followup - ).deliver_now - - @outgoing_message.record_email_delivery( - mail_message.to_addrs.join(', '), - mail_message.message_id - ) - @outgoing_message.info_request.reopen_to_new_responses - + # OutgoingMailer.followup() depends on DB id of the + # outgoing message, save just before sending. @outgoing_message.save! + begin + mail_message = OutgoingMailer.followup( + @outgoing_message.info_request, + @outgoing_message, + @outgoing_message.incoming_message_followup + ).deliver_now + rescue StandardError => e + @outgoing_message.record_email_failure(e.message) + else + @outgoing_message.record_email_delivery( + mail_message.to_addrs.join(', '), + mail_message.message_id + ) + + @outgoing_message.info_request.reopen_to_new_responses + ensure + # Ensure DB is updated to isolate potential templating issues + # from impacting delivery status information. + @outgoing_message.save! + end + if @outgoing_message.what_doing == 'internal_review' flash[:notice] = _("Your internal review request has been sent on its way.") else diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 19620a70ae..763ab68f9a 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -405,21 +405,33 @@ def new # This automatically saves dependent objects, such as @outgoing_message, in the same transaction @info_request.save! - # TODO: Sending the message needs the database id, so we send after - # saving, which isn't ideal if the request broke here. if @outgoing_message.sendable? - mail_message = OutgoingMailer.initial_request( - @outgoing_message.info_request, - @outgoing_message - ).deliver_now - - @outgoing_message.record_email_delivery( - mail_message.to_addrs.join(', '), - mail_message.message_id - ) + begin + mail_message = OutgoingMailer.initial_request( + @outgoing_message.info_request, + @outgoing_message + ).deliver_now + rescue StandardError => e + # Catch a wide variety of potential ActionMailer failures and + # record the exception reason so administrators don't have to + # dig into logs. + @outgoing_message.record_email_failure( + e.message + ) + else + @outgoing_message.record_email_delivery( + mail_message.to_addrs.join(', '), + mail_message.message_id + ) + + flash[:request_sent] = true + ensure + # Ensure the InfoRequest is fully updated before templating to + # isolate templating issues recording delivery status. + @info_request.save! + end end - flash[:request_sent] = true redirect_to show_request_path(:url_title => @info_request.url_title) end diff --git a/app/models/info_request.rb b/app/models/info_request.rb index b1c0799074..c89bf3d673 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -671,6 +671,10 @@ def self.log_overdue_event_type(event_type) end + def self.request_sent_types + %w(sent resent followup_sent followup_resent send_error) + end + # Possible reasons that a request could be reported for administrator attention def report_reasons [_("Contains defamatory material"), @@ -1115,7 +1119,7 @@ def calculate_last_event_forming_initial_request expecting_clarification = true end - if %w(sent resent followup_sent followup_resent).include?(event.event_type) + if self.class.request_sent_types.include?(event.event_type) if last_sent.nil? last_sent = event elsif event.event_type == 'resent' diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index 21555200d8..b7987d53c2 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -51,7 +51,8 @@ class InfoRequestEvent < ActiveRecord::Base 'very_overdue', # the request becomes very overdue 'embargo_expiring', # an embargo is about to expire 'expire_embargo', # an embargo on the request expires - 'set_embargo' # an embargo is added or extended + 'set_embargo', # an embargo is added or extended + 'send_error' # an error during sending ].freeze belongs_to :info_request, diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index 23f1a3cf18..06287d904e 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -196,6 +196,18 @@ def is_owning_user?(user) info_request.is_owning_user?(user) end + # Without recording the send failure, parts of the public and admin + # interfaces for the request and authority may become inaccessible. + def record_email_failure(failure_reason) + self.last_sent_at = Time.zone.now + self.status = 'failed' + save! + + info_request.log_event('send_error', { :reason => failure_reason, + :outgoing_message_id => id }) + set_info_request_described_state + end + def record_email_delivery(to_addrs, message_id, log_event_type = 'sent') self.last_sent_at = Time.zone.now self.status = 'sent' @@ -268,13 +280,20 @@ def mail_server_logs end def delivery_status - mail_server_logs.map(&:delivery_status).compact.reject(&:unknown?).last || - MailServerLog::DeliveryStatus.new(:unknown) + # If the outgoing status is failed, we won't have mail logs, and know we can + # present a failed status to the end user. + if status == 'failed' + MailServerLog::DeliveryStatus.new(:failed) + else + mail_server_logs.map(&:delivery_status).compact.reject(&:unknown?).last || + MailServerLog::DeliveryStatus.new(:unknown) + end end # An admin function def prepare_message_for_resend - if MESSAGE_TYPES.include?(message_type) and status == 'sent' + if MESSAGE_TYPES.include?(message_type) && + (status == 'sent' || status == 'failed') self.status = 'ready' else raise "Message id #{id} has type '#{message_type}' status " \ @@ -348,7 +367,9 @@ def default_letter=(text) private def set_info_request_described_state - if message_type == 'initial_request' + if status == 'failed' + info_request.set_described_state('error_message') + elsif message_type == 'initial_request' info_request.set_described_state('waiting_response') elsif message_type == 'followup' if info_request.described_state == 'waiting_clarification' diff --git a/app/views/request/_correspondence.html.erb b/app/views/request/_correspondence.html.erb index a6263c8dc9..331411090e 100644 --- a/app/views/request/_correspondence.html.erb +++ b/app/views/request/_correspondence.html.erb @@ -2,7 +2,7 @@ <% case info_request_event.event_type %> <% when 'response' %> <%= render :partial => 'request/incoming_correspondence', :locals => { :incoming_message => info_request_event.incoming_message } %> -<% when 'sent', 'followup_sent' %> +<% when 'sent', 'followup_sent', 'send_error' %> <%= render :partial => 'request/outgoing_correspondence', :locals => { :outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> <% when 'resent', 'followup_resent' %> <%= render :partial => 'request/resent_outgoing_correspondence', :locals => { :outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> From 1b08dd6fcd6b22ae4bd02069fc1851b4c0278656 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Fri, 15 Mar 2019 11:14:03 +0000 Subject: [PATCH 027/114] Handle specific errors rather than catch everything with StandardError Otherwise unexpected errors will be silently rescued rather than being picked up by ExceptionNotifier. And in the original form would mean that tests always pass. List of errors adapted from: https://stackoverflow.com/questions/9194418/what-exceptions-can-be-raised-by-action-mailer --- app/controllers/followups_controller.rb | 16 +++++++++++++++- app/controllers/request_controller.rb | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/controllers/followups_controller.rb b/app/controllers/followups_controller.rb index 60f16c9cc5..686c3dc880 100644 --- a/app/controllers/followups_controller.rb +++ b/app/controllers/followups_controller.rb @@ -143,13 +143,27 @@ def send_followup # outgoing message, save just before sending. @outgoing_message.save! + errors = [ EOFError, + IOError, + Timeout::Error, + Errno::ECONNRESET, + Errno::ECONNABORTED, + Errno::EPIPE, + Errno::ETIMEDOUT, + Net::SMTPAuthenticationError, + Net::SMTPServerBusy, + Net::SMTPSyntaxError, + Net::SMTPUnknownError, + OpenSSL::SSL::SSLError ] + errors << AWS::SES::ResponseError if defined?(AWS::SES::ResponseError) + begin mail_message = OutgoingMailer.followup( @outgoing_message.info_request, @outgoing_message, @outgoing_message.incoming_message_followup ).deliver_now - rescue StandardError => e + rescue *errors => e @outgoing_message.record_email_failure(e.message) else @outgoing_message.record_email_delivery( diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 763ab68f9a..0e52c9df9e 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -405,13 +405,27 @@ def new # This automatically saves dependent objects, such as @outgoing_message, in the same transaction @info_request.save! + errors = [ EOFError, + IOError, + Timeout::Error, + Errno::ECONNRESET, + Errno::ECONNABORTED, + Errno::EPIPE, + Errno::ETIMEDOUT, + Net::SMTPAuthenticationError, + Net::SMTPServerBusy, + Net::SMTPSyntaxError, + Net::SMTPUnknownError, + OpenSSL::SSL::SSLError ] + errors << AWS::SES::ResponseError if defined?(AWS::SES::ResponseError) + if @outgoing_message.sendable? begin mail_message = OutgoingMailer.initial_request( @outgoing_message.info_request, @outgoing_message ).deliver_now - rescue StandardError => e + rescue *errors => e # Catch a wide variety of potential ActionMailer failures and # record the exception reason so administrators don't have to # dig into logs. From b517b46ba88d1df9b7260b6f2a55628727361407 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 21 Mar 2019 13:54:00 +0100 Subject: [PATCH 028/114] Extract allowed send errors into OutgoingMessage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And in the theme, you can override everything or just add in the new like this: ``` OutgoingMessage.instance_eval do def additional_send_errors [ 'custom error from theme' ] end end ``` ``` $ bundle exec rails c > OutgoingMessage.expected_send_errors => [EOFError, IOError, … "custom error from theme"] ``` --- app/controllers/followups_controller.rb | 16 +--------------- app/controllers/request_controller.rb | 16 +--------------- app/models/outgoing_message.rb | 19 +++++++++++++++++++ spec/models/outgoing_message_spec.rb | 19 +++++++++++++++++++ 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/app/controllers/followups_controller.rb b/app/controllers/followups_controller.rb index 686c3dc880..026165b478 100644 --- a/app/controllers/followups_controller.rb +++ b/app/controllers/followups_controller.rb @@ -143,27 +143,13 @@ def send_followup # outgoing message, save just before sending. @outgoing_message.save! - errors = [ EOFError, - IOError, - Timeout::Error, - Errno::ECONNRESET, - Errno::ECONNABORTED, - Errno::EPIPE, - Errno::ETIMEDOUT, - Net::SMTPAuthenticationError, - Net::SMTPServerBusy, - Net::SMTPSyntaxError, - Net::SMTPUnknownError, - OpenSSL::SSL::SSLError ] - errors << AWS::SES::ResponseError if defined?(AWS::SES::ResponseError) - begin mail_message = OutgoingMailer.followup( @outgoing_message.info_request, @outgoing_message, @outgoing_message.incoming_message_followup ).deliver_now - rescue *errors => e + rescue *OutgoingMessage.expected_send_errors => e @outgoing_message.record_email_failure(e.message) else @outgoing_message.record_email_delivery( diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 0e52c9df9e..0f4bfbd2f9 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -405,27 +405,13 @@ def new # This automatically saves dependent objects, such as @outgoing_message, in the same transaction @info_request.save! - errors = [ EOFError, - IOError, - Timeout::Error, - Errno::ECONNRESET, - Errno::ECONNABORTED, - Errno::EPIPE, - Errno::ETIMEDOUT, - Net::SMTPAuthenticationError, - Net::SMTPServerBusy, - Net::SMTPSyntaxError, - Net::SMTPUnknownError, - OpenSSL::SSL::SSLError ] - errors << AWS::SES::ResponseError if defined?(AWS::SES::ResponseError) - if @outgoing_message.sendable? begin mail_message = OutgoingMailer.initial_request( @outgoing_message.info_request, @outgoing_message ).deliver_now - rescue *errors => e + rescue *OutgoingMessage.expected_send_errors => e # Catch a wide variety of potential ActionMailer failures and # record the exception reason so administrators don't have to # dig into logs. diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index 06287d904e..de758fcf6d 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -74,6 +74,25 @@ class OutgoingMessage < ActiveRecord::Base self.default_url_options[:protocol] = "https" end + def self.expected_send_errors + [ EOFError, + IOError, + Timeout::Error, + Errno::ECONNRESET, + Errno::ECONNABORTED, + Errno::EPIPE, + Errno::ETIMEDOUT, + Net::SMTPAuthenticationError, + Net::SMTPServerBusy, + Net::SMTPSyntaxError, + Net::SMTPUnknownError, + OpenSSL::SSL::SSLError ].concat(additional_send_errors) + end + + def self.additional_send_errors + [] + end + def self.default_salutation(public_body) _("Dear {{public_body_name}},", :public_body_name => public_body.name) end diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index 894db6e8df..d2645c154b 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -66,6 +66,25 @@ end + describe '.expected_send_errors' do + subject { described_class.expected_send_errors } + class TestError < StandardError ; end + + it { is_expected.to be_an(Array) } + it { is_expected.to include(IOError) } + it { is_expected.to_not include(TestError) } + + context '.additional_send_errors has been overriden to include a custom error' do + before do + allow(described_class).to receive(:additional_send_errors). + and_return([ TestError ]) + end + + it { is_expected.to include(TestError) } + end + + end + describe '#initialize' do it 'does not censor the #body' do From 1b876691dddddc2f221fc22b2c64fea6638f763a Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 21 Mar 2019 16:58:32 +0100 Subject: [PATCH 029/114] Allow send_error events to be treated as a special kind of send event Needed for the change to InfoRequest#calculate_last_event_forming_initial_request work as expected and to prevent introducing a bug in InfoRequestEvent#is_request_sending? The pre-existing event types related to message sending are divided into 'send' and 'resend' which relate to the original outgoing_message (initial request) and 'send_followup' and 'resend_followup' which are used for events relating to followup messages. The new event type for 'send_error' is shared between the 2 types of outgoing message. Rather than complicate the main 'send_error' code, this commit adds some extra logic that checks message_type to differentiate between events relating to the initial request and events relating to followup messages. This prevents 'send_error' events for followup messages unintentionally being treated as a change to the request itself. (A send error for a followup message should not be returned as the last event forming an initial request, but a send error related to an initial request message should be treated as a request sending event.) --- app/models/info_request.rb | 4 +++- app/models/info_request_event.rb | 4 +++- spec/factories/info_request_events.rb | 26 ++++++++++++++++++++++++++ spec/models/info_request_event_spec.rb | 20 ++++++++++++++++++++ spec/models/info_request_spec.rb | 25 +++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/app/models/info_request.rb b/app/models/info_request.rb index c89bf3d673..1337a3c668 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -1122,7 +1122,9 @@ def calculate_last_event_forming_initial_request if self.class.request_sent_types.include?(event.event_type) if last_sent.nil? last_sent = event - elsif event.event_type == 'resent' + elsif event.event_type == 'resent' || + (event.event_type == 'send_error' && + event.outgoing_message.message_type == 'initial_request') last_sent = event elsif expecting_clarification && event.event_type == 'followup_sent' # TODO: this needs to cope with followup_resent, which it doesn't. diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index b7987d53c2..709eeabe4d 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -377,7 +377,9 @@ def resets_due_dates? end def is_request_sending? - ['sent', 'resent'].include?(event_type) + ['sent', 'resent'].include?(event_type) || + (event_type == 'send_error' && + outgoing_message.message_type == 'initial_request') end def is_clarification? diff --git a/spec/factories/info_request_events.rb b/spec/factories/info_request_events.rb index f21513966f..63177e333b 100644 --- a/spec/factories/info_request_events.rb +++ b/spec/factories/info_request_events.rb @@ -30,6 +30,19 @@ info_request { outgoing_message.info_request } end + factory :failed_sent_request_event do + event_type 'send_error' + association :outgoing_message, factory: :initial_request + params_yaml "---\n:reason: Connection timed out" + info_request { outgoing_message.info_request.reload } + + after(:create) do |evnt, evaluator| + evnt.params_yaml += "\noutgoing_message_id: #{evnt.outgoing_message.id}" + evnt.outgoing_message.status = 'failed' + evnt.info_request.described_state = 'error_message' + end + end + factory :response_event do event_type 'response' incoming_message @@ -48,6 +61,19 @@ info_request { outgoing_message.info_request } end + factory :failed_sent_followup_event do + event_type 'send_error' + association :outgoing_message, factory: :new_information_followup + params_yaml "---\n:reason: Connection timed out" + info_request { outgoing_message.info_request.reload } + + after(:create) do |evnt, evaluator| + evnt.params_yaml += "\noutgoing_message_id: #{evnt.outgoing_message.id}" + evnt.outgoing_message.status = 'failed' + evnt.info_request.described_state = 'error_message' + end + end + factory :comment_event do event_type 'comment' association :comment diff --git a/spec/models/info_request_event_spec.rb b/spec/models/info_request_event_spec.rb index 35db3d58d9..2d57552e75 100644 --- a/spec/models/info_request_event_spec.rb +++ b/spec/models/info_request_event_spec.rb @@ -702,6 +702,16 @@ expect(event.resets_due_dates?).to be true end + it 'returns true if the event is a failed send of a request' do + info_request_event = FactoryBot.create(:failed_sent_request_event) + expect(info_request_event.resets_due_dates?).to be true + end + + it 'returns false if the event is a failed send of a followup' do + info_request_event = FactoryBot.create(:failed_sent_followup_event) + expect(info_request_event.resets_due_dates?).to be false + end + it 'returns false if the event is neither a sending of the request or a clarification' do info_request_event = FactoryBot.create(:response_event) @@ -722,6 +732,16 @@ expect(info_request_event.is_request_sending?).to be true end + it 'returns true if the event is a failed send of a request' do + info_request_event = FactoryBot.create(:failed_sent_request_event) + expect(info_request_event.is_request_sending?).to be true + end + + it 'returns false if the event is a failed send of a followup' do + info_request_event = FactoryBot.create(:failed_sent_followup_event) + expect(info_request_event.is_request_sending?).to be false + end + it 'returns false if the event type is not "sent" or "resent"' do info_request_event = FactoryBot.create(:response_event) expect(info_request_event.is_request_sending?).to be false diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 57b49c9275..f1a4b00d4c 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -4057,6 +4057,17 @@ def email_and_raw_email(opts = {}) .to raise_error(RuntimeError) end + it 'returns the most recent "send_error" event after an error sending the request' do + outgoing_message = info_request.outgoing_messages.first + outgoing_message.record_email_failure('sending stopped by test') + + failure_event = info_request. + info_request_events.reload. + detect{ |e| e.event_type == 'send_error'} + expect(info_request.last_event_forming_initial_request). + to eq failure_event + end + end context 'when there is no value in the database' do @@ -4102,6 +4113,20 @@ def email_and_raw_email(opts = {}) .to eq followup_event end + it 'returns the most recent "send_error" event after an error sending a request' do + outgoing_message = info_request.outgoing_messages.first + outgoing_message.record_email_failure('sending stopped by test') + # manually unset the id so that it has to be recalculated + info_request. + update_attribute(:last_event_forming_initial_request_id, nil) + + failure_event = info_request. + info_request_events.reload. + detect{ |e| e.event_type == 'send_error'} + expect(info_request.last_event_forming_initial_request). + to eq failure_event + end + it 'raises an error if the request has never been sent' do info_request.info_request_events.destroy_all expect{ info_request.last_event_forming_initial_request } From 49c0ec448ebf3f48088b8ef01981316643487254 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Fri, 22 Mar 2019 17:55:04 +0000 Subject: [PATCH 030/114] Specs for OutgoingMessage#record_email_failure --- spec/models/outgoing_message_spec.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index d2645c154b..8b18094dfc 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -1808,6 +1808,34 @@ class TestError < StandardError ; end end + describe '#record_email_failure' do + let(:outgoing_message) { FactoryBot.create(:initial_request) } + subject { outgoing_message.record_email_failure('Exception#message') } + + it 'sets the status to "failed"' do + subject + expect(outgoing_message.status).to eq 'failed' + end + + it 'records the reason for the failure in the event log' do + subject + event = outgoing_message.info_request.info_request_events.last + expect(event.event_type).to eq('send_error') + expect(event.params[:reason]).to eq('Exception#message') + end + + it 'sets described_state to "error_message"' do + subject + expect(outgoing_message.info_request.described_state). + to eq 'error_message' + end + + it 'updates OutgoingMessage#last_sent_at' do + expect{ subject }.to change{ outgoing_message.last_sent_at } + end + + end + end describe OutgoingMessage, " when making an outgoing message" do From 1797b4403d88b072b2391b8d573cccda4e2594a5 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Fri, 22 Mar 2019 18:09:33 +0000 Subject: [PATCH 031/114] Controller specs for handling followup and request sending errors --- spec/controllers/followups_controller_spec.rb | 16 +++++++ spec/controllers/request_controller_spec.rb | 25 +++++++++++ ...examples_for_network_errors_during_send.rb | 45 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 spec/support/shared_examples_for_network_errors_during_send.rb diff --git a/spec/controllers/followups_controller_spec.rb b/spec/controllers/followups_controller_spec.rb index 64283e9921..9bfcc0d69f 100644 --- a/spec/controllers/followups_controller_spec.rb +++ b/spec/controllers/followups_controller_spec.rb @@ -424,6 +424,22 @@ expect(response).to render_template('new') end + context 'a network error occurs while sending a followup' do + + def send_request + post :create, params: { + outgoing_message: dummy_message, + request_id: request.id, + incoming_message_id: message_id + } + end + + let(:outgoing_message) { request.reload.outgoing_messages.last } + + it_behaves_like 'NetworkSendErrors' + + end + it_behaves_like 'successful_followup_sent' it "updates the status for successful followup sends" do diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index f037bdfce7..9ce416eb2e 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -1146,6 +1146,31 @@ def expect_hidden(hidden_template) end + context 'a network error occurs while sending the initial request' do + + def send_request + session[:user_id] = @user.id + post :new, params: { + info_request: { + public_body_id: @body.id, + title: 'Test request', + tag_string: '' + }, + outgoing_message: { + body: 'This is a silly letter.' + }, + submitted_new_request: 1, + preview: 0 + } + end + + let(:request) { assigns[:info_request] } + let(:outgoing_message) { request.reload.outgoing_messages.last } + + it_behaves_like 'NetworkSendErrors' + + end + it "should redirect pros to the pro version" do with_feature_enabled(:alaveteli_pro) do pro_user = FactoryBot.create(:pro_user) diff --git a/spec/support/shared_examples_for_network_errors_during_send.rb b/spec/support/shared_examples_for_network_errors_during_send.rb new file mode 100644 index 0000000000..3f8b6bbc1c --- /dev/null +++ b/spec/support/shared_examples_for_network_errors_during_send.rb @@ -0,0 +1,45 @@ +# -*- encoding : utf-8 -*- +require 'spec_helper' + +shared_examples_for 'NetworkSendErrors' do + + describe 'handles a network error during message sending' do + + before do + allow_any_instance_of(ActionMailer::MessageDelivery). + to receive(:deliver_now). + and_raise(Errno::ETIMEDOUT) + + send_request + end + + it 'does not send the email' do + deliveries = ActionMailer::Base.deliveries + expect(deliveries.size).to eq(0) + end + + it 'sets the described_state of the request to "error_message"' do + expect(request.reload.described_state).to eq('error_message') + end + + it 'logs a "send_error" event' do + event = request.reload.info_request_events.last + expect(event.event_type).to eq 'send_error' + end + + it 'stores the reason for the failure' do + event = request.reload.info_request_events.last + expect(event.params[:reason]).to eq 'Connection timed out' + end + + it 'ensures that the outgoing message is persisted' do + expect(outgoing_message).to be_persisted + end + + it 'ensures that the outgoing message status is set to "failed"' do + expect(outgoing_message.status).to eq 'failed' + end + + end + +end From 932b51035a3f9aa2259ec6a07233db616dcea766 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 3 Apr 2019 17:38:40 +0100 Subject: [PATCH 032/114] Spec for OutgoingMessage#delivery_status --- spec/models/outgoing_message_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index 8b18094dfc..8387e1420d 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -1656,6 +1656,12 @@ class TestError < StandardError ; end describe '#delivery_status' do + it 'returns a failed status if the message send failed' do + message = FactoryBot.create(:failed_sent_request_event).outgoing_message + status = MailServerLog::DeliveryStatus.new(:failed) + expect(message.delivery_status).to eq(status) + end + it 'returns an unknown delivery status if there are no mail logs' do message = FactoryBot.create(:initial_request) allow(message).to receive(:mail_server_logs).and_return([]) From 6f53668461e81400626195f561d4bd73c717db8f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 3 Apr 2019 18:32:07 +0100 Subject: [PATCH 033/114] Add specs for OutgoingMessage#prepare_message_for_resend --- spec/models/outgoing_message_spec.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index 8387e1420d..37521ab54a 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -1814,6 +1814,32 @@ class TestError < StandardError ; end end + describe '#prepare_message_for_resend' do + let(:outgoing_message) { FactoryBot.build(:initial_request) } + subject { outgoing_message.prepare_message_for_resend } + + it 'raises an error if it receives an unexpected message_type' do + allow(outgoing_message).to receive(:message_type).and_return('fake') + expect{ subject }.to raise_error(RuntimeError) + end + + it 'raises an error if it receives an unexpected status' do + outgoing_message.status = 'ready' + expect{ subject }.to raise_error(RuntimeError) + end + + it 'sets status to "ready" if the current status is "sent"' do + outgoing_message.status = 'sent' + expect{ subject }.to change{ outgoing_message.status }.to('ready') + end + + it 'sets status to "ready" if the current status is "failed"' do + outgoing_message.status = 'failed' + expect{ subject }.to change{ outgoing_message.status }.to('ready') + end + + end + describe '#record_email_failure' do let(:outgoing_message) { FactoryBot.create(:initial_request) } subject { outgoing_message.record_email_failure('Exception#message') } From fe23bc592e32e1dff54d39afae076bb6a2c2ab6f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Apr 2019 15:25:27 +0100 Subject: [PATCH 034/114] Display message send failures on the admin summary page --- app/views/admin_general/_to_do_list.html.erb | 2 +- .../admin_general/_to_do_list.html.erb_spec.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/views/admin_general/_to_do_list.html.erb b/app/views/admin_general/_to_do_list.html.erb index d3accff4d0..673408fb53 100644 --- a/app/views/admin_general/_to_do_list.html.erb +++ b/app/views/admin_general/_to_do_list.html.erb @@ -38,7 +38,7 @@ <% end %> - <% if item.described_state == 'attention_requested' %> + <% if item.last_event.params[:reason] %> Reason diff --git a/spec/views/admin_general/_to_do_list.html.erb_spec.rb b/spec/views/admin_general/_to_do_list.html.erb_spec.rb index f45cb8ce88..084328f2b5 100644 --- a/spec/views/admin_general/_to_do_list.html.erb_spec.rb +++ b/spec/views/admin_general/_to_do_list.html.erb_spec.rb @@ -56,6 +56,22 @@ def render_errors(items) end end + context 'the message send failed due to a network error' do + let(:request) do + FactoryBot.create(:failed_sent_request_event).info_request + end + + it 'describes an error message rather than a user message' do + render_errors(items) + expect(rendered).to include('Reason') + end + + it 'shows the reason given for the failed send' do + render_errors(items) + expect(rendered).to include('Connection timed out') + end + end + context 'comment reported as requiring admin attention' do let(:comment) do FactoryBot.create(:attention_requested_comment, From 3c764307de08fd1aa1cdb7527e2cd1cf3a1a5194 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Sat, 29 Jun 2019 23:10:57 +1200 Subject: [PATCH 035/114] Add flash messages for request/followup email failures. --- app/controllers/followups_controller.rb | 23 +++++++++++++++++------ app/controllers/request_controller.rb | 5 +++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/controllers/followups_controller.rb b/app/controllers/followups_controller.rb index 026165b478..4947495ad7 100644 --- a/app/controllers/followups_controller.rb +++ b/app/controllers/followups_controller.rb @@ -150,25 +150,36 @@ def send_followup @outgoing_message.incoming_message_followup ).deliver_now rescue *OutgoingMessage.expected_send_errors => e + authority_name = @outgoing_message.info_request.public_body.name @outgoing_message.record_email_failure(e.message) + if @outgoing_message.what_doing == 'internal_review' + flash[:error] = _("Your internal review request has been saved but " \ + "not yet sent to {{authority_name}} due to an error.", + authority_name: authority_name) + else + flash[:error] = _("Your follow up message has been saved but not yet " \ + "sent to {{authority_name}} due to an error.", + authority_name: authority_name) + end else @outgoing_message.record_email_delivery( mail_message.to_addrs.join(', '), mail_message.message_id ) + if @outgoing_message.what_doing == 'internal_review' + flash[:notice] = _("Your internal review request has been sent on " \ + "its way.") + else + flash[:notice] = _("Your follow up message has been sent on its way.") + end + @outgoing_message.info_request.reopen_to_new_responses ensure # Ensure DB is updated to isolate potential templating issues # from impacting delivery status information. @outgoing_message.save! end - - if @outgoing_message.what_doing == 'internal_review' - flash[:notice] = _("Your internal review request has been sent on its way.") - else - flash[:notice] = _("Your follow up message has been sent on its way.") - end end def set_incoming_message diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 0f4bfbd2f9..2a7fd4629d 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -418,6 +418,11 @@ def new @outgoing_message.record_email_failure( e.message ) + + flash[:error] = _("An error occurred while sending your request to " \ + "{{authority_name}} but has been saved and flagged " \ + "for administrator attention.", + authority_name: @info_request.public_body.name) else @outgoing_message.record_email_delivery( mail_message.to_addrs.join(', '), From 30736274bff12c84bed95ca9e1faea9982c36a9c Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 3 Jul 2019 10:23:56 +0100 Subject: [PATCH 036/114] Minor style fixes * Hash style * Redundant curly braces around a hash parameter --- app/models/outgoing_message.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index de758fcf6d..cc955f6d29 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -222,8 +222,8 @@ def record_email_failure(failure_reason) self.status = 'failed' save! - info_request.log_event('send_error', { :reason => failure_reason, - :outgoing_message_id => id }) + info_request.log_event('send_error', reason: failure_reason, + outgoing_message_id: id) set_info_request_described_state end From 12763b486837c7d1fb76a2bc425b1d13671aa08e Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 3 Jul 2019 16:44:14 +0100 Subject: [PATCH 037/114] Update changelog --- doc/CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 98988d6661..0f2201f521 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -2,6 +2,9 @@ ## Highlighted Features +* Improve error handling when sending request-related emails (initial request + mails and followups) - failed messages are captured and a send_error event is + logged to make it easier for site admins to see what's happened (Nigel Jones) * Fixed bug where expiring embargoes were not fully removed from batches when the related requests reached the publication data (Liz Conlan) From 0aba92edd107b40ef8c301abfdb2ca6b10ee303f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 27 Jun 2019 15:27:48 +0100 Subject: [PATCH 038/114] Make pro_user factories create an accompanying pro_account --- .../alaveteli_pro/subscriptions_controller_spec.rb | 13 +++++++++++-- spec/factories/users.rb | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb b/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb index ba8714937e..c1313cfdf4 100644 --- a/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb @@ -549,7 +549,11 @@ def successful_signup context 'user has no Stripe id' do - let(:user) { FactoryBot.create(:pro_user) } + let(:user) do + user = FactoryBot.create(:pro_user) + user.pro_account.update(stripe_customer_id: nil) + user + end before do session[:user_id] = user.id @@ -677,9 +681,14 @@ def successful_signup context 'user has no Stripe id' do - let(:user) { FactoryBot.create(:pro_user) } + let(:user) do + user = FactoryBot.create(:pro_user) + user.pro_account.update(stripe_customer_id: nil) + user + end before do + user.pro_account.update(stripe_customer_id: nil) session[:user_id] = user.id end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 9e0be1fda4..87d320eee7 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -62,6 +62,7 @@ sequence(:name) { |n| "Pro User #{n}" } after(:create) do |user, evaluator| user.add_role :pro + create(:pro_account, user: user) end end From d9d69259a618f3d61d93aea36613357fc1d6c98b Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 14:42:22 +0100 Subject: [PATCH 039/114] Lock stripe-ruby-mock gem to '< 2.5.7' Unless we upgrade from a 3.x to a 4.x version of the stripe gem upgrading stripe-ruby-mock above 2.5.6 adds an undocumented dependency on version 4.12.0+ of the stripe gem (where the Stripe::Discount object was first added[1]). Untested assumption but it seems likely that we would need to move to a newer Stripe API version to be able to upgrade the stripe gem. Avoids spec error: NameError: uninitialized constant Stripe::Discount [1] https://github.com/stripe/stripe-ruby/commit/160028ada110357c91740f26958dd7add399415f --- Gemfile | 2 +- Gemfile.lock | 4 ++-- Gemfile.rails_next.lock | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 954ff78941..358a4094c0 100644 --- a/Gemfile +++ b/Gemfile @@ -166,7 +166,7 @@ group :test do gem 'coveralls', '~> 0.8.0', :require => false gem 'capybara', '~> 3.5.0' gem 'delorean', '~> 2.1.0' - gem 'stripe-ruby-mock', '~> 2.5.4' + gem 'stripe-ruby-mock', ['~> 2.5.4', '< 2.5.7'] gem('rails-controller-testing') end diff --git a/Gemfile.lock b/Gemfile.lock index 1d2f6ba80b..4b998dc284 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -374,7 +374,7 @@ GEM statistics2 (0.54) stripe (3.4.1) faraday (~> 0.10) - stripe-ruby-mock (2.5.5) + stripe-ruby-mock (2.5.6) dante (>= 0.2.0) multi_json (~> 1.0) stripe (>= 2.0.3) @@ -498,7 +498,7 @@ DEPENDENCIES statistics2 (~> 0.54) strip_attributes! stripe (~> 3.4.1) - stripe-ruby-mock (~> 2.5.4) + stripe-ruby-mock (~> 2.5.4, < 2.5.7) syslog_protocol (~> 0.9.0) therubyracer (~> 0.12.0) thin (~> 1.5.0, < 1.6.0) diff --git a/Gemfile.rails_next.lock b/Gemfile.rails_next.lock index af96342061..4be98e758b 100644 --- a/Gemfile.rails_next.lock +++ b/Gemfile.rails_next.lock @@ -374,7 +374,7 @@ GEM statistics2 (0.54) stripe (3.4.1) faraday (~> 0.10) - stripe-ruby-mock (2.5.5) + stripe-ruby-mock (2.5.6) dante (>= 0.2.0) multi_json (~> 1.0) stripe (>= 2.0.3) @@ -498,7 +498,7 @@ DEPENDENCIES statistics2 (~> 0.54) strip_attributes! stripe (~> 3.4.1) - stripe-ruby-mock (~> 2.5.4) + stripe-ruby-mock (~> 2.5.4, < 2.5.7) syslog_protocol (~> 0.9.0) therubyracer (~> 0.12.0) thin (~> 1.5.0, < 1.6.0) From 400a69d3cbbd0844d71fcd6a3e737e8ec25558df Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 3 Jul 2019 18:55:30 +0100 Subject: [PATCH 040/114] Monkeypatch StripeMock to let us test past_due subscriptions Adds a new helper method to set the subscription status to 'past_due' as it can't be done directly - setting status directly is not supported by the Stripe API so can not be allowed by StripeMock - and StripeMock does not currently model subscriptions which become past_due or unpaid once the payment date passes (with or without a failed payment) so there's no existing behaviour for us to backport to our locked version. There is an open issue for adding this behaviour dataing back to late 2015 but no suitable solution was found: https://github.com/rebelidealist/stripe-ruby-mock/issues/286 This commit provides a partial implementation of the idea in the issue comments of adding something like the the StripeMock.prepare_card_error helper method to mock the expected status: https://github.com/rebelidealist/stripe-ruby-mock/issues/286#issuecomment-320541778 --- lib/stripe_mock_patch.rb | 46 ++++++++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 lib/stripe_mock_patch.rb diff --git a/lib/stripe_mock_patch.rb b/lib/stripe_mock_patch.rb new file mode 100644 index 0000000000..d2144222ce --- /dev/null +++ b/lib/stripe_mock_patch.rb @@ -0,0 +1,46 @@ +require 'stripe_mock/request_handlers/subscriptions.rb' + +# Monkeypatch StripeMock to allow mocking a past_due subscription status +module StripeMock + ## + # helper method to set the status to 'past_due' + def self.mark_subscription_as_past_due(subscription) + ::Stripe::Subscription.update(subscription.id, + metadata: { marked_past_due: true }) + end + + module RequestHandlers::Subscriptions + # copies current method and adds a call to our + # set_custom_status_from_metatdata method to set the status + # from the stored info in the subscription metatdata when the + # subscription is retrieved (including calling #refresh) + def retrieve_subscription(route, method_url, params, headers) + route =~ method_url + + set_custom_status_from_metadata(subscriptions[$1]) if subscriptions[$1] + assert_existence :subscription, $1, subscriptions[$1] + end + + # copies current method and adds a call to our + # set_custom_status_from_metatdata method to set the status + # from the stored info in the subscription metatdata when multiple + # subscriptions are retrieved (including from `Subscription::List`) + def retrieve_subscriptions(route, method_url, params, headers) + route =~ method_url + + subscriptions.values.each do |subscription| + set_custom_status_from_metadata(subscription) + end + + Data.mock_list_object(subscriptions.values, params) + end + + private + + def set_custom_status_from_metadata(subscription) + if subscription[:metadata][:marked_past_due] + subscription.merge!(status: 'past_due') + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7ae5cf2921..2f00d8bdae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,7 @@ require 'simplecov' require 'coveralls' require 'webmock/rspec' +require 'stripe_mock_patch' require "alaveteli_features/spec_helpers" cov_formats = [Coveralls::SimpleCov::Formatter] @@ -279,4 +280,3 @@ def get_last_post_redirect normalise_whitespace(actual) == normalise_whitespace(expected) end end - From f2530b017e5ab75df62563982c2f62e627200f4f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 26 Jun 2019 15:20:13 +0100 Subject: [PATCH 041/114] Add existing pro metrics script as a new class * Derive the stripe plans from stripe_namespace rather than hardcoding * Make stripe data lookup conditional on pro_pricing being enabled * Rename "Canceled Users" as "Pending User Cancelations" Since we set this up, we've discovered that - as we have cancellations configured to take effect at the end of the billing cycle - this number actually represents _pending_ cancellations. Processed cancellations can be derived instead from deleted subscription events. * Add attributes for report start and end dates * Look up new Stripe subscribers * Look up cancelled Stripe subscribers * Make data more machine-readable * Extract stripe_report_data into its own method * Rename new_users to new_and_returning_users Stripe returns new signups which includes both new users and users who have previously cancelled and returned - which is why there's sometimes a discrepancy between our count of new users and the Stripe API's * Add specs for past_due user count * Add specs for reporting subscription ids * Extract appending subscription ids to a memo to a new method * Add 'pricing disabled'/'pricing enabled' contexts Co-Authored-By: Gareth Rees --- config/initializers/alaveteli.rb | 1 + lib/alaveteli_pro/metrics_report.rb | 179 +++++++++++++++ spec/lib/alaveteli_pro/metrics_report_spec.rb | 213 ++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 lib/alaveteli_pro/metrics_report.rb create mode 100644 spec/lib/alaveteli_pro/metrics_report_spec.rb diff --git a/config/initializers/alaveteli.rb b/config/initializers/alaveteli.rb index 92ad72a758..b0ea880d45 100644 --- a/config/initializers/alaveteli.rb +++ b/config/initializers/alaveteli.rb @@ -64,6 +64,7 @@ require 'typeahead_search' require 'alaveteli_mail_poller' require 'safe_redirect' +require 'alaveteli_pro/metrics_report' AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales, AlaveteliConfiguration::default_locale) diff --git a/lib/alaveteli_pro/metrics_report.rb b/lib/alaveteli_pro/metrics_report.rb new file mode 100644 index 0000000000..f57f649a87 --- /dev/null +++ b/lib/alaveteli_pro/metrics_report.rb @@ -0,0 +1,179 @@ +module AlaveteliPro + ## + # A class to encapsulate composing a data structure of reporting data for + # Pro user activity from a mix of database and Stripe API sources + class MetricsReport + include AlaveteliFeatures::Helpers + + attr_reader :report_start, :report_end + + def initialize + @report_start = 1.week.ago.beginning_of_day + @report_end = Time.zone.yesterday.end_of_day + end + + def report_data + data = + { + new_pro_requests: number_of_requests_created_this_week, + total_new_requests: estimated_number_of_pro_requests, + new_batches: number_of_batch_requests_created_this_week, + new_signups: number_of_pro_signups_this_week, + total_accounts: total_number_of_pro_accounts, + active_accounts: number_of_pro_accounts_active_this_week + } + + data.merge!(stripe_report_data) if feature_enabled?(:pro_pricing) + data + end + + def stripe_report_data + return {} unless feature_enabled?(:pro_pricing) + + data = + { + paying_users: stripe_data[:paid], + discounted_users: stripe_data[:discount], + trialing_users: stripe_data[:trialing], + past_due_users: { + count: stripe_data[:past_due], + subs: stripe_data[:past_due_users] + }, + pending_cancellations: { + count: stripe_data[:canceled], + subs: stripe_data[:canceled_users] + }, + unknown_users: stripe_data[:unknown] + } + + data.merge!(new_stripe_users) + data.merge!(cancelled_stripe_users) + data + end + + private + + def number_of_requests_created_this_week + InfoRequest.pro. + where(["info_requests.created_at >= ?", report_start]).count + end + + def estimated_number_of_pro_requests + User.where(id: ProAccount.pluck(:user_id)).map.sum do |user| + # TODO: also scope to subscription closed_at + user.info_requests. + where('created_at >= ?', user.pro_account.created_at). + count + end + end + + def number_of_batch_requests_created_this_week + InfoRequestBatch. + where(["created_at >= ? AND embargo_duration IS NOT NULL", + report_start]).count + end + + def number_of_pro_signups_this_week + ProAccount. + where("pro_accounts.created_at >= ?", report_start). + count + end + + def total_number_of_pro_accounts + ProAccount.count + end + + def number_of_pro_accounts_active_this_week + events = %w(comment set_embargo sent followup_sent status_update) + + User.pro.includes(:info_request_events). + where(['info_request_events.created_at > ? AND ' \ + 'info_request_events.event_type in (?)', + report_start, events]). + references(:info_request_events).count + end + + def stripe_plans + prefix = + if AlaveteliConfiguration.stripe_namespace.blank? + '' + else + "#{AlaveteliConfiguration.stripe_namespace}-" + end + ["#{prefix}pro", "#{prefix}pro-annual-billing"] + end + + def new_stripe_users + count = 0 + sub_ids = [] + stripe_plans.each do |plan_id| + begin + Stripe::Subscription.list( + 'created[gte]': report_start.to_i, + 'created[lte]': report_end.to_i, + plan: plan_id + ).auto_paging_each do |item| + if item.plan.id == plan_id + count += 1 + sub_ids << item.id + end + end + rescue Stripe::InvalidRequestError + # tried to fetch a plan that's not set up + end + end + { new_and_returning_users: { count: count, subs: sub_ids } } + end + + def cancelled_stripe_users + count = 0 + sub_ids = [] + list = Stripe::Event.list( + 'created[gte]': report_start.to_i, + 'created[lte]': report_end.to_i, + 'type': 'customer.subscription.deleted' + ).auto_paging_each do |item| + # there's no filter for plan in the Event API so we need to ignore + # any cancellations which aren't ours + if stripe_plans.include?(item.data.object.plan.id) + count += 1 + sub_ids << item.data.object.id + end + end + + { canceled_users: { count: count, subs: sub_ids } } + end + + def append_sub(memo, sub) + if memo == 0 + [sub.id] + else + memo << sub.id + end + end + + def stripe_data + @wdtk_subs ||= + Stripe::Subscription.list.auto_paging_each. + select { |s| stripe_plans.include?(s.plan.id) }. + each_with_object(Hash.new(0)) do |sub, memo| + if sub.status == 'canceled' || sub.cancel_at_period_end + memo[:canceled] += 1 + memo[:canceled_users] = append_sub(memo[:canceled_users], sub) + elsif sub.status == 'active' && !sub.discount + memo[:paid] += 1 + elsif sub.status == 'active' && sub.discount + memo[:discount] += 1 + elsif sub.status == 'trialing' + memo[:trialing] += 1 + elsif sub.status == 'past_due' + memo[:past_due] += 1 + memo[:past_due_users] = append_sub(memo[:past_due_users], sub) + else + # Shouldn't ever be > 0 + memo[:unknown] += 1 + end + end + end + end +end diff --git a/spec/lib/alaveteli_pro/metrics_report_spec.rb b/spec/lib/alaveteli_pro/metrics_report_spec.rb new file mode 100644 index 0000000000..c8d51d2de4 --- /dev/null +++ b/spec/lib/alaveteli_pro/metrics_report_spec.rb @@ -0,0 +1,213 @@ +require 'spec_helper' +require 'stripe_mock' + +describe AlaveteliPro::MetricsReport do + before { StripeMock.start } + after { StripeMock.stop } + let(:stripe_helper) { StripeMock.create_test_helper } + let!(:pro_plan) { stripe_helper.create_plan(id: 'pro', amount: 10) } + + let!(:pro_annual_plan) do + stripe_helper.create_plan(id: 'pro-annual-billing', amount: 100) + end + + describe '#report_data' do + subject { described_class.new.report_data } + + let(:user) { FactoryBot.create(:user) } + let(:pro_user) { FactoryBot.create(:pro_user) } + + before do + 2.times { FactoryBot.create(:info_request, user: user) } + 3.times { FactoryBot.create(:info_request, user: pro_user) } + FactoryBot.create(:info_request_batch, + :sent, + :embargoed, + user: pro_user) + + time_travel_to(2.weeks.ago) { + pro = FactoryBot.create(:pro_user) + FactoryBot.create(:info_request, user: pro) + } + end + + context 'without pricing enabled' do + it 'does not calculate Stripe data' do + expect(subject).to_not include(:paying_users) + end + end + + context 'with pricing enabled', feature: :pro_pricing do + it 'includes Stripe data' do + expect(subject).to include(:paying_users) + end + end + + it { is_expected.to be_a(Hash) } + + it 'does not include non-pro requests in requests made count' do + expect(subject[:new_pro_requests]).to eq 4 + end + + it 'does not include non-pro requests in requests made count' do + expect(subject[:new_pro_requests]).to eq 4 + end + + it 'returns the total number of Pro requests' do + expect(subject[:total_new_requests]).to eq 5 + end + + it 'returns the number of batch requests' do + expect(subject[:new_batches]).to eq 1 + end + + it 'returns the number of new Pro accounts' do + expect(subject[:new_signups]).to eq 1 + end + + it 'returns the number of Pro accounts' do + expect(subject[:total_accounts]).to eq 2 + end + + it 'does not include non-pro activity in the active user count' do + expect(subject[:active_accounts]).to eq 1 + end + end + + describe '#stripe_report_data' do + subject { described_class.new.stripe_report_data } + + it { is_expected.to be_a(Hash) } + + context 'with pricing disabled' do + it { is_expected.to eq({}) } + end + + context 'with pricing enabled', feature: :pro_pricing do + let(:customer) do + Stripe::Customer.create(email: 'user@localhost', + source: stripe_helper.generate_card_token) + end + + let(:coupon) do + stripe_helper.create_coupon(id: 'half_off', + percent_off: 50, + duration: 'forever') + end + + let!(:paid_sub) do + Stripe::Subscription.create(customer: customer, + plan: pro_plan.id) + end + + let!(:paid_annual_sub) do + Stripe::Subscription.create(customer: customer, + plan: pro_annual_plan.id) + end + + let!(:half_price_sub) do + Stripe::Subscription.create(customer: customer, + plan: pro_plan.id, + coupon: coupon.id) + end + + let!(:trial_sub) do + Stripe::Subscription.create(customer: customer, + plan: pro_plan.id, + trial_period_days: 360, + trial_end: (Time.now + 9.days).to_i) + end + + let!(:pending_cancel_sub) do + subscription = Stripe::Subscription.create(customer: customer, + plan: pro_plan.id) + + # note - in later API versions, at_period_end is no longer + # available for delete so we'd have to call something like + # this instead: + # Stripe::Subscription.update(subscription.id, + # cancel_at_period_end: true) + subscription.delete(at_period_end: true) + subscription + end + + let!(:past_due_sub) do + subscription = Stripe::Subscription.create(customer: customer, + plan: pro_plan.id,) + StripeMock.mark_subscription_as_past_due(subscription) + subscription + end + + it 'returns the number of users paying the full rate' do + expect(subject[:paying_users]).to eq 2 + end + + it 'returns the number of discounted users' do + expect(subject[:discounted_users]).to eq 1 + end + + it 'returns the number of trialing users' do + expect(subject[:trialing_users]).to eq 1 + end + + describe 'returning pending cancellation data' do + it 'returns the number of users with pending cancellations' do + expect(subject[:pending_cancellations][:count]).to eq 1 + end + + it 'returns the subscriber ids of users with pending cancellations' do + expect(subject[:pending_cancellations][:subs]). + to eq([pending_cancel_sub.id]) + end + end + + describe 'returning past due data' do + it 'returns the number of past due users' do + expect(subject[:past_due_users][:count]).to eq 1 + end + + it 'returns the subscriber ids of past due users' do + expect(subject[:past_due_users][:subs]).to eq([past_due_sub.id]) + end + end + + describe 'returning new Stripe user data' do + it 'returns the number of new Stripe users' do + expect(subject[:new_and_returning_users][:count]).to eq 6 + end + + it 'returns the subscriber ids of new Stripe users' do + expected = + [ paid_sub.id, paid_annual_sub.id, half_price_sub.id, + trial_sub.id, pending_cancel_sub.id, past_due_sub.id ] + expect(subject[:new_and_returning_users][:subs]). + to match_array(expected) + end + end + + describe 'returning cancelled user data' do + let(:unrelated_plan) do + stripe_helper.create_plan(id: 'not_ours', amount: 4) + end + + before do + StripeMock.mock_webhook_event('customer.subscription.deleted', + plan: pro_plan) + StripeMock.mock_webhook_event('customer.subscription.deleted', + plan: pro_annual_plan) + StripeMock.mock_webhook_event('customer.subscription.deleted', + plan: unrelated_plan) + end + + it 'returns the number of cancelled users' do + expect(subject[:canceled_users][:count]).to eq 2 + end + + it 'returns the subscription ids for cancelled users' do + expect(subject[:canceled_users][:subs]). + to eq(['su_00000000000000', 'su_00000000000000']) + end + end + end + end +end From 5f629004cfd855186385f8c739eacdd80b3b24ec Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 16:50:07 +0100 Subject: [PATCH 042/114] Add Pro Metrics weekly email --- app/mailers/alaveteli_pro/metrics_mailer.rb | 28 +++++ .../metrics_mailer/weekly_report.text.erb | 31 +++++ lib/alaveteli_pro/metrics_report.rb | 8 +- spec/lib/alaveteli_pro/metrics_report_spec.rb | 12 ++ .../alaveteli_pro/metrics_mailer_spec.rb | 114 ++++++++++++++++++ 5 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 app/mailers/alaveteli_pro/metrics_mailer.rb create mode 100644 app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb create mode 100644 spec/mailers/alaveteli_pro/metrics_mailer_spec.rb diff --git a/app/mailers/alaveteli_pro/metrics_mailer.rb b/app/mailers/alaveteli_pro/metrics_mailer.rb new file mode 100644 index 0000000000..594f254dbb --- /dev/null +++ b/app/mailers/alaveteli_pro/metrics_mailer.rb @@ -0,0 +1,28 @@ +module AlaveteliPro + ## + # A mailer responsible for sending out the weekly metrics report to + # the Pro contact + # + class MetricsMailer < ApplicationMailer + def self.send_weekly_report(report = AlaveteliPro::MetricsReport.new) + weekly_report(report).deliver_now + end + + def weekly_report(report) + @data = report.report_data + @pricing_enabled = report.includes_pricing_data? + @report_start = report.report_start + @report_end = report.report_end + + set_auto_generated_headers + + subject = _("{{pro_site_name}} Weekly Metrics", + pro_site_name: AlaveteliConfiguration.pro_site_name.html_safe) + + mail(from: pro_contact_from_name_and_email, + to: pro_contact_from_name_and_email, + subject: subject + ) + end + end +end diff --git a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb new file mode 100644 index 0000000000..6104e279de --- /dev/null +++ b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb @@ -0,0 +1,31 @@ +<%= _("Weekly Pro Metrics report for {{start_date}} - {{end_date}}", + start_date: @report_start.strftime('%d %B %Y'), + end_date: @report_end.strftime('%d %B %Y')) %> + + +<%- if @pricing_enabled %> +<%= _('Number of paying users:') %> <%= @data[:paying_users] %> +<%= _('Number of free trial users:') %> <%= @data[:trialing_users] %> +<%= _('Number of discounted users:') %> <%= @data[:discounted_users] %> +<% end %> +<%= _('Total number of Pro accounts:') %> <%= @data[:total_accounts] %> +<%= _('Number of Pro accounts active this week:') %> <%= @data[:active_accounts] %> + +<%= _('New batches made this week:') %> <%= @data[:new_batches] %> +<%= _('New Pro requests this week:') %> <%= @data[:new_pro_requests] %> +<%= _('Total requests made this week:') %> <%= @data[:total_new_requests] %> + +<%- if !@pricing_enabled %> +<%= _('New Pro accounts this week:') %> <%= @data[:new_signups] %> +<% else %> +<%= _('New Pro subscriptions this week:') %> <%= @data[:new_and_returning_users][:count] %> +<%- if @data[:new_and_returning_users][:count] - @data[:new_signups] > 0 %> +<%= n_("(includes {{count}} returning subscriber)", + "(includes {{count}} returning subscribers)", + @data[:new_and_returning_users][:count] - @data[:new_signups], + count: @data[:new_and_returning_users][:count] - @data[:new_signups]) %> +<% end %> +<%= _('Cancelled subscriptions:') %> <%= @data[:canceled_users][:count] %> +<%= _('Pending cancellations:') %> <%= @data[:pending_cancellations][:count] %> +<%= _('Payments past due:') %> <%= @data[:past_due_users][:count] %> +<% end %> diff --git a/lib/alaveteli_pro/metrics_report.rb b/lib/alaveteli_pro/metrics_report.rb index f57f649a87..1a9e12416d 100644 --- a/lib/alaveteli_pro/metrics_report.rb +++ b/lib/alaveteli_pro/metrics_report.rb @@ -12,6 +12,10 @@ def initialize @report_end = Time.zone.yesterday.end_of_day end + def includes_pricing_data? + feature_enabled?(:pro_pricing) + end + def report_data data = { @@ -23,12 +27,12 @@ def report_data active_accounts: number_of_pro_accounts_active_this_week } - data.merge!(stripe_report_data) if feature_enabled?(:pro_pricing) + data.merge!(stripe_report_data) if includes_pricing_data? data end def stripe_report_data - return {} unless feature_enabled?(:pro_pricing) + return {} unless includes_pricing_data? data = { diff --git a/spec/lib/alaveteli_pro/metrics_report_spec.rb b/spec/lib/alaveteli_pro/metrics_report_spec.rb index c8d51d2de4..f166bc4703 100644 --- a/spec/lib/alaveteli_pro/metrics_report_spec.rb +++ b/spec/lib/alaveteli_pro/metrics_report_spec.rb @@ -11,6 +11,18 @@ stripe_helper.create_plan(id: 'pro-annual-billing', amount: 100) end + describe '#includes_pricing_data?' do + subject { described_class.new.includes_pricing_data? } + + context 'with pricing disabled' do + it { is_expected.to eq(false) } + end + + context 'with pricing enabled', feature: :pro_pricing do + it { is_expected.to eq(true) } + end + end + describe '#report_data' do subject { described_class.new.report_data } diff --git a/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb new file mode 100644 index 0000000000..6eb153211f --- /dev/null +++ b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb @@ -0,0 +1,114 @@ +require 'spec_helper' + +RSpec.describe AlaveteliPro::MetricsMailer do + let(:data) do + { + new_pro_requests: 104, + total_new_requests: 37535, + new_batches: 3, + new_signups: 5, + total_accounts: 284, + active_accounts: 42, + paying_users: 44, + discounted_users: 7, + trialing_users: 8, + past_due_users: { count: 0, subs: 0 }, + pending_cancellations: + { count: 2, subs: ['sub_1234', 'sub_1235'] }, + unknown_users: 0, + new_and_returning_users: + { count: 6, + subs: + ['sub_1236', + 'sub_1237', + 'sub_1238', + 'sub_1239', + 'sub_1240', + 'sub_1241'] }, + canceled_users: { count: 0, subs: [] } + } + end + + let(:report) do + report = AlaveteliPro::MetricsReport.new + allow(report).to receive(:report_data).and_return(data) + report + end + + let(:message) { AlaveteliPro::MetricsMailer.weekly_report(report).message } + + describe '.send_weekly_report' do + subject { described_class.send_weekly_report(report) } + + it 'should deliver the weekly_report email' do + expect { subject }.to( + change(ActionMailer::Base.deliveries, :size).by(1) + ) + end + end + + describe '#weekly_report' do + it 'sends the email to the pro contact address' do + expect(message.to).to eq [AlaveteliConfiguration.pro_contact_email] + end + + it 'sends the email from the pro contact address' do + expect(message.from).to eq [AlaveteliConfiguration.pro_contact_email] + end + + it 'has a subject including "Weekly Metrics"' do + expect(message.subject).to match('Weekly Metrics') + end + + it 'includes the number of Pro accounts' do + expect(message.body).to include('Total number of Pro accounts: 284') + end + + context 'pro pricing disabled' do + it 'does not include paying user info' do + expect(message.body).to_not include('Number of paying users: 44') + end + + it 'reports the number of new Pro accounts' do + expect(message.body).to include('New Pro accounts this week: 5') + end + + it 'does not report the number of new Pro subscriptions' do + expect(message.body).to_not include('New Pro subscriptions this week:') + end + end + + context 'pro pricing enabled', feature: :pro_pricing do + it 'reports the number of new Pro subscriptions' do + expect(message.body).to include('New Pro subscriptions this week: 6') + end + + it 'does not report the number of new Pro accounts' do + expect(message.body).to_not include('New Pro accounts this week:') + end + + it 'includes paying user info' do + expect(message.body).to include('Number of paying users: 44') + end + + describe 'returning subscribers' do + it 'correctly calculates the number of returning subscribers' do + expect(message.body). + to include('(includes 1 returning subscriber)') + end + + it 'pluralises "subscriber"' do + data[:new_and_returning_users][:count] = 7 + expect(message.body). + to include('(includes 2 returning subscribers)') + end + + it 'does not show the returning subscribers note if there are none' do + data[:new_and_returning_users][:count] = 5 + expect(message.body). + to_not include('(includes 0 returning subscriber') + end + end + end + end +end From f21e51a79a6bd69e350b3cc8db3f72afdac997aa Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 17:14:43 +0100 Subject: [PATCH 043/114] Add MetricsMailer preview --- .../alaveteli_pro/metrics_mailer_preview.rb | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb diff --git a/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb b/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb new file mode 100644 index 0000000000..1e0919758a --- /dev/null +++ b/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb @@ -0,0 +1,39 @@ +require 'rspec/mocks/standalone' + +module AlaveteliPro + class MetricsMailerPreview < ActionMailer::Preview + def weekly_report + data = + { + new_pro_requests: 104, + total_new_requests: 37535, + new_batches: 3, + new_signups: 5, + total_accounts: 284, + active_accounts: 42, + paying_users: 44, + discounted_users: 7, + trialing_users: 8, + past_due_users: { count: 0, subs: 0 }, + pending_cancellations: + { count: 2, subs: ['sub_1234', 'sub_1235'] }, + unknown_users: 0, + new_and_returning_users: + { count: 6, + subs: + ['sub_1236', + 'sub_1237', + 'sub_1238', + 'sub_1239', + 'sub_1240', + 'sub_1241'] }, + canceled_users: { count: 0, subs: [] } + } + + report = MetricsReport.new + report.stub(report_data: data) + + MetricsMailer.weekly_report(report) + end + end +end From 664e899b12fdce95b760a83ce4a1fe1b380c63b7 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 17:21:32 +0100 Subject: [PATCH 044/114] List new, cancelled, cancellation pending and past due users in email ...with links to the subscription page in the Stripe dashboard Introduces extra space between lines of data to make the email easier to read --- .../metrics_mailer/weekly_report.text.erb | 29 +++++++++++++++++++ .../alaveteli_pro/metrics_mailer_spec.rb | 12 ++++++++ 2 files changed, 41 insertions(+) diff --git a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb index 6104e279de..b131005210 100644 --- a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb +++ b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb @@ -5,14 +5,20 @@ <%- if @pricing_enabled %> <%= _('Number of paying users:') %> <%= @data[:paying_users] %> + <%= _('Number of free trial users:') %> <%= @data[:trialing_users] %> + <%= _('Number of discounted users:') %> <%= @data[:discounted_users] %> + <% end %> <%= _('Total number of Pro accounts:') %> <%= @data[:total_accounts] %> + <%= _('Number of Pro accounts active this week:') %> <%= @data[:active_accounts] %> <%= _('New batches made this week:') %> <%= @data[:new_batches] %> + <%= _('New Pro requests this week:') %> <%= @data[:new_pro_requests] %> + <%= _('Total requests made this week:') %> <%= @data[:total_new_requests] %> <%- if !@pricing_enabled %> @@ -25,7 +31,30 @@ @data[:new_and_returning_users][:count] - @data[:new_signups], count: @data[:new_and_returning_users][:count] - @data[:new_signups]) %> <% end %> +<%- if @data[:new_and_returning_users][:count] > 0 %> +<%- @data[:new_and_returning_users][:subs].each do |sub| %> + * https://dashboard.stripe.com/subscriptions/<%= sub %> +<% end %> +<% end %> + <%= _('Cancelled subscriptions:') %> <%= @data[:canceled_users][:count] %> +<%- if @data[:canceled_users][:count] > 0 %> +<%- @data[:canceled_users][:subs].each do |sub| %> + * https://dashboard.stripe.com/subscriptions/<%= sub %> +<% end %> +<% end %> + <%= _('Pending cancellations:') %> <%= @data[:pending_cancellations][:count] %> +<%- if @data[:pending_cancellations][:count] > 0 %> +<%- @data[:pending_cancellations][:subs].each do |sub| %> + * https://dashboard.stripe.com/subscriptions/<%= sub %> +<% end %> +<% end %> + <%= _('Payments past due:') %> <%= @data[:past_due_users][:count] %> +<%- if @data[:past_due_users][:count] > 0 %> +<%- @data[:past_due_users][:subs].each do |sub| %> + * https://dashboard.stripe.com/subscriptions/<%= sub %> +<% end %> +<% end %> <% end %> diff --git a/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb index 6eb153211f..5228bff5b4 100644 --- a/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb @@ -109,6 +109,18 @@ to_not include('(includes 0 returning subscriber') end end + + describe 'listing subscriber dashboard links' do + it 'should include an indented bullet point list' do + expect(message.body).to include( + <<~TXT + Pending cancellations: 2 + * https://dashboard.stripe.com/subscriptions/sub_1234 + * https://dashboard.stripe.com/subscriptions/sub_1235 + TXT + ) + end + end end end end From 6d13bd54041e1d6085821f3194fd8f0f4cdd0de3 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 17:23:10 +0100 Subject: [PATCH 045/114] Simplify email template * Reduce number of conditionals (wasn't a big enough improvement on reading order of the email to be worth the extra template complexity) * Remove the checks on [:count] > 0 where possible when showing sub data - As it stands the pending cancellations and past dues come from the main autopaging loop in MetricsReport#stripe_data which sets the initial data as 0 rather than an empty array so we still need to have the check there for those until we resolve that --- .../metrics_mailer/weekly_report.text.erb | 30 ++++++++----------- .../alaveteli_pro/metrics_mailer_spec.rb | 11 +++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb index b131005210..8e41d1c970 100644 --- a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb +++ b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb @@ -10,20 +10,6 @@ <%= _('Number of discounted users:') %> <%= @data[:discounted_users] %> -<% end %> -<%= _('Total number of Pro accounts:') %> <%= @data[:total_accounts] %> - -<%= _('Number of Pro accounts active this week:') %> <%= @data[:active_accounts] %> - -<%= _('New batches made this week:') %> <%= @data[:new_batches] %> - -<%= _('New Pro requests this week:') %> <%= @data[:new_pro_requests] %> - -<%= _('Total requests made this week:') %> <%= @data[:total_new_requests] %> - -<%- if !@pricing_enabled %> -<%= _('New Pro accounts this week:') %> <%= @data[:new_signups] %> -<% else %> <%= _('New Pro subscriptions this week:') %> <%= @data[:new_and_returning_users][:count] %> <%- if @data[:new_and_returning_users][:count] - @data[:new_signups] > 0 %> <%= n_("(includes {{count}} returning subscriber)", @@ -31,18 +17,14 @@ @data[:new_and_returning_users][:count] - @data[:new_signups], count: @data[:new_and_returning_users][:count] - @data[:new_signups]) %> <% end %> -<%- if @data[:new_and_returning_users][:count] > 0 %> <%- @data[:new_and_returning_users][:subs].each do |sub| %> * https://dashboard.stripe.com/subscriptions/<%= sub %> <% end %> -<% end %> <%= _('Cancelled subscriptions:') %> <%= @data[:canceled_users][:count] %> -<%- if @data[:canceled_users][:count] > 0 %> <%- @data[:canceled_users][:subs].each do |sub| %> * https://dashboard.stripe.com/subscriptions/<%= sub %> <% end %> -<% end %> <%= _('Pending cancellations:') %> <%= @data[:pending_cancellations][:count] %> <%- if @data[:pending_cancellations][:count] > 0 %> @@ -57,4 +39,16 @@ * https://dashboard.stripe.com/subscriptions/<%= sub %> <% end %> <% end %> +<% else %> +<%= _('New Pro accounts this week:') %> <%= @data[:new_signups] %> <% end %> + +<%= _('Total number of Pro accounts:') %> <%= @data[:total_accounts] %> + +<%= _('Number of Pro accounts active this week:') %> <%= @data[:active_accounts] %> + +<%= _('New batches made this week:') %> <%= @data[:new_batches] %> + +<%= _('New Pro requests this week:') %> <%= @data[:new_pro_requests] %> + +<%= _('Total requests made this week:') %> <%= @data[:total_new_requests] %> diff --git a/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb index 5228bff5b4..7c919b73de 100644 --- a/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/metrics_mailer_spec.rb @@ -120,6 +120,17 @@ TXT ) end + + it 'should not include a list if there are no pending cancellations' do + data[:pending_cancellations][:count] = 0 + data[:pending_cancellations][:subs] = 0 + expect(message.body).to include( + <<~TXT + Pending cancellations: 0 + + TXT + ) + end end end end From bd81bef980aed2975078dbb5ddd65d2f19f3491b Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 4 Jul 2019 17:24:10 +0100 Subject: [PATCH 046/114] Send the Pro Metrics email once a week --- config/crontab-example | 3 +++ script/send-pro-metrics-report | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 script/send-pro-metrics-report diff --git a/config/crontab-example b/config/crontab-example index cdfb2ae0d5..16daec1576 100644 --- a/config/crontab-example +++ b/config/crontab-example @@ -43,6 +43,9 @@ MAILTO=!!(*= $mailto *)!! # Once a week (very early Monday morning) 54 2 * * 1 !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/cleanup-holding-pen +# Once a week (early Monday morning) +37 8 * * 1 !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/commonlib/bin/run-with-lockfile.sh -n !!(*= $vhost_dir *)!!/send-pro-metrics-report.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/send-pro-metrics-report || echo "stalled?" + # Once a year :) 0 0 1 11 * !!(*= $user *)!! !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/send-public-holiday-reminder diff --git a/script/send-pro-metrics-report b/script/send-pro-metrics-report new file mode 100644 index 0000000000..79f6434d9e --- /dev/null +++ b/script/send-pro-metrics-report @@ -0,0 +1,4 @@ +#!/bin/bash +TOP_DIR="$(dirname "$BASH_SOURCE")/.." +cd "$TOP_DIR" +bundle exec rails runner 'AlaveteliPro::MetricsMailer.send_weekly_report' From f60c71bd9d74483353a85c24f402333b35fd5f7b Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 10 Jul 2019 17:27:14 +0100 Subject: [PATCH 047/114] Update changelog --- doc/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 0f2201f521..04eeccc4c0 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -2,6 +2,7 @@ ## Highlighted Features +* Send weekly metrics email to the Pro Admin team (Liz Conlan, Gareth Rees) * Improve error handling when sending request-related emails (initial request mails and followups) - failed messages are captured and a send_error event is logged to make it easier for site admins to see what's happened (Nigel Jones) From bfeee7e66be981f2eba40e9888f8f733726e5a47 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 11 Jul 2019 12:07:44 +0100 Subject: [PATCH 048/114] Reinstate public/alavetelitheme in .gitignore This symlink gets created when switching themes to point at the theme's public directory. alavetelitheme -> /home/vagrant/alaveteli-themes/whatdotheyknow-theme/public --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 450f33d9bb..ecc4965fbf 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ locale/model_attributes.rb log/* old-cache/ public/*theme/ +public/alavetelitheme public/asktheeu-theme public/assets/ public/down.current.html From da3699958c77930c478cb60bb09f4869c634c480 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 11 Jul 2019 12:22:28 +0100 Subject: [PATCH 049/114] Rename Pro Metrics 'Total requests made this week' report label 'Total requests made this week' wasn't a good description of the reported data. 'Estimated total number of Pro requests' is clearer. Also changes the data key from `:total_new_requests` to `:estimated_total_pro_requests` --- app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb | 2 +- lib/alaveteli_pro/metrics_report.rb | 2 +- spec/lib/alaveteli_pro/metrics_report_spec.rb | 4 ++-- spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb index 8e41d1c970..915c86bd08 100644 --- a/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb +++ b/app/views/alaveteli_pro/metrics_mailer/weekly_report.text.erb @@ -51,4 +51,4 @@ <%= _('New Pro requests this week:') %> <%= @data[:new_pro_requests] %> -<%= _('Total requests made this week:') %> <%= @data[:total_new_requests] %> +<%= _('Estimated total number of Pro requests:') %> <%= @data[:estimated_total_pro_requests] %> diff --git a/lib/alaveteli_pro/metrics_report.rb b/lib/alaveteli_pro/metrics_report.rb index 1a9e12416d..73b80c2c3c 100644 --- a/lib/alaveteli_pro/metrics_report.rb +++ b/lib/alaveteli_pro/metrics_report.rb @@ -20,7 +20,7 @@ def report_data data = { new_pro_requests: number_of_requests_created_this_week, - total_new_requests: estimated_number_of_pro_requests, + estimated_total_pro_requests: estimated_number_of_pro_requests, new_batches: number_of_batch_requests_created_this_week, new_signups: number_of_pro_signups_this_week, total_accounts: total_number_of_pro_accounts, diff --git a/spec/lib/alaveteli_pro/metrics_report_spec.rb b/spec/lib/alaveteli_pro/metrics_report_spec.rb index f166bc4703..1a43959f66 100644 --- a/spec/lib/alaveteli_pro/metrics_report_spec.rb +++ b/spec/lib/alaveteli_pro/metrics_report_spec.rb @@ -65,8 +65,8 @@ expect(subject[:new_pro_requests]).to eq 4 end - it 'returns the total number of Pro requests' do - expect(subject[:total_new_requests]).to eq 5 + it 'returns the estimated (total) number of Pro requests' do + expect(subject[:estimated_total_pro_requests]).to eq 5 end it 'returns the number of batch requests' do diff --git a/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb b/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb index 1e0919758a..32297f36a4 100644 --- a/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb +++ b/spec/mailers/previews/alaveteli_pro/metrics_mailer_preview.rb @@ -6,7 +6,7 @@ def weekly_report data = { new_pro_requests: 104, - total_new_requests: 37535, + estimated_total_pro_requests: 37535, new_batches: 3, new_signups: 5, total_accounts: 284, From e809c3ba5521357b97f7c53d70ac28691b4a4c77 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 11 Jul 2019 12:42:27 +0100 Subject: [PATCH 050/114] Add line break after each webhook customer Makes it easier to distinguish sublists in some mail clients. --- app/views/alaveteli_pro/webhook_mailer/digest.text.erb | 1 + spec/mailers/alaveteli_pro/webhook_mailer_spec.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/views/alaveteli_pro/webhook_mailer/digest.text.erb b/app/views/alaveteli_pro/webhook_mailer/digest.text.erb index 77d342600f..55d832095e 100644 --- a/app/views/alaveteli_pro/webhook_mailer/digest.text.erb +++ b/app/views/alaveteli_pro/webhook_mailer/digest.text.erb @@ -3,4 +3,5 @@ <%- webhooks.each do |webhook| %> - <%= webhook.state %> <% end %> + <% end %> diff --git a/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb index 013046852e..fa4d8eaa0a 100644 --- a/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb +++ b/spec/mailers/alaveteli_pro/webhook_mailer_spec.rb @@ -68,6 +68,7 @@ * https://dashboard.stripe.com/customers/cus_123 - state_a - state_b + * https://dashboard.stripe.com/customers/cus_456 - state_a TXT From 6ab2e1f68513db4871fc5e92abe7050b11605733 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Fri, 12 Jul 2019 07:31:16 +0100 Subject: [PATCH 051/114] Add configuration setting to enable pro_pricing --- config/general.yml-example | 9 +++++++++ config/initializers/alaveteli_features.rb | 8 ++++++++ lib/configuration.rb | 1 + 3 files changed, 18 insertions(+) diff --git a/config/general.yml-example b/config/general.yml-example index 6ee2cb87aa..b05d5d2d13 100644 --- a/config/general.yml-example +++ b/config/general.yml-example @@ -1243,3 +1243,12 @@ STRIPE_WEBHOOK_SECRET: '' # PRO_REFERRAL_COUPON: 'PROREFERRAL' # --- PRO_REFERRAL_COUPON: '' + +# If ENABLE_PRO_PRICING is set to true, Alaveteli let users enter their bank +# details and subscribe to a Stripe subscription which grants them access to the +# pro role and all the features of Alaveteli Professional. +# +# ENABLE_PRO_PRICING – Boolean (default: false) +# +# --- +ENABLE_PRO_PRICING: false diff --git a/config/initializers/alaveteli_features.rb b/config/initializers/alaveteli_features.rb index 60d6a25ca9..0521131a7a 100644 --- a/config/initializers/alaveteli_features.rb +++ b/config/initializers/alaveteli_features.rb @@ -23,3 +23,11 @@ else AlaveteliFeatures.backend.disable(:alaveteli_pro) unless !AlaveteliFeatures.backend.enabled?(:alaveteli_pro) end + +# Pro Pricing +# We enable pro_pricing globally based on the ENABLE_PRO_PRICING config +if AlaveteliConfiguration.enable_pro_pricing + AlaveteliFeatures.backend.enable(:pro_pricing) unless AlaveteliFeatures.backend.enabled?(:pro_pricing) +else + AlaveteliFeatures.backend.disable(:pro_pricing) unless !AlaveteliFeatures.backend.enabled?(:pro_pricing) +end diff --git a/lib/configuration.rb b/lib/configuration.rb index 9a65d9cda7..6ee1c58db2 100644 --- a/lib/configuration.rb +++ b/lib/configuration.rb @@ -50,6 +50,7 @@ module AlaveteliConfiguration :ENABLE_TWO_FACTOR_AUTH => false, :ENABLE_WIDGETS => false, :ENABLE_ALAVETELI_PRO => false, + :ENABLE_PRO_PRICING => false, :EXCEPTION_NOTIFICATIONS_FROM => 'errors@localhost', :EXCEPTION_NOTIFICATIONS_TO => 'user-support@localhost', :FORCE_REGISTRATION_ON_NEW_REQUEST => false, From 9720c875b7edd274cdb4379da50decb1ae52995b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 12 Jul 2019 12:04:44 +0100 Subject: [PATCH 052/114] Add template pro help page Just a placeholder that will get overridden by a theme. --- app/views/help/pro.html.erb | 1 + config/routes.rb | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 app/views/help/pro.html.erb diff --git a/app/views/help/pro.html.erb b/app/views/help/pro.html.erb new file mode 100644 index 0000000000..7a96d0e810 --- /dev/null +++ b/app/views/help/pro.html.erb @@ -0,0 +1 @@ +Placeholder to be overriden by theme diff --git a/config/routes.rb b/config/routes.rb index 8b7202ee24..77910125f9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -392,6 +392,13 @@ match '/help/credits' => 'help#credits', :as => :help_credits, :via => :get + + constraints FeatureConstraint.new(:alaveteli_pro) do + match '/help/pro' => 'help#pro', + as: :help_pro, + via: :get + end + match '/help/:template' => 'help#action', :as => :help_general, :via => :get, From 63f811d0287380faa0452b61a193ba2704af06d6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 12 Jul 2019 12:08:20 +0100 Subject: [PATCH 053/114] Add more pro screenshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These will mostly be used in the pro help page. Uses the generic “none” theme so that themes can override if they wish. --- .../alaveteli-pro/screenshot-batch-privacy.jpg | Bin 0 -> 235215 bytes .../alaveteli-pro/screenshot-batch-write.jpg | Bin 0 -> 293227 bytes .../screenshot-embargo-extension.jpg | Bin 0 -> 11477 bytes .../screenshot-embargo-publish.jpg | Bin 0 -> 10961 bytes .../alaveteli-pro/screenshot-embargo.jpg | Bin 0 -> 11650 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/assets/images/alaveteli-pro/screenshot-batch-privacy.jpg create mode 100644 app/assets/images/alaveteli-pro/screenshot-batch-write.jpg create mode 100644 app/assets/images/alaveteli-pro/screenshot-embargo-extension.jpg create mode 100644 app/assets/images/alaveteli-pro/screenshot-embargo-publish.jpg create mode 100644 app/assets/images/alaveteli-pro/screenshot-embargo.jpg diff --git a/app/assets/images/alaveteli-pro/screenshot-batch-privacy.jpg b/app/assets/images/alaveteli-pro/screenshot-batch-privacy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..210715cfe0a3224b57209f2c83f1bd02ec3061ce GIT binary patch literal 235215 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̄f=d!1?KUeOPk%J$Z*gRF`PYE#@ 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 HXXzVJJ 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%0D|j{=vPUg)OUG;8^<|*&Iy_&_LVD{| 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

0=KI;nKo8~)VA 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
<%= form_tag(subscriptions_path, id: 'pro-signup') do %>
-

Selected plan

+

<%= _('Selected plan') %>

<%= @plan.name %> @@ -60,7 +60,7 @@
-

Terms and conditions

+

<%= _('Terms and conditions') %>

<%= render partial: 'alaveteli_pro/pages/legal' %> From 61d6229c96c42a3d4e46abfd38b468746e1a5ee7 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Mon, 15 Jul 2019 13:38:19 +0100 Subject: [PATCH 056/114] Prefer single quoted strings --- app/views/alaveteli_pro/plans/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/alaveteli_pro/plans/show.html.erb b/app/views/alaveteli_pro/plans/show.html.erb index 24a55b96e6..264bb17e6f 100644 --- a/app/views/alaveteli_pro/plans/show.html.erb +++ b/app/views/alaveteli_pro/plans/show.html.erb @@ -28,7 +28,7 @@
-

<%= _("Upgrade account") %>

+

<%= _('Upgrade account') %>

From e411b64ace9d4a181a9b46285a62e7c3bdf03b69 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 16 Jul 2019 15:29:26 +0100 Subject: [PATCH 057/114] Set the Stripe API version in the initializer Locks the Stripe API version so that all API calls are made using a single known version rather than defaulting to the version associated with the Stripe account as this cannot be changed to an older version when a new account is created - it can only ever be upgraded to the latest. --- config/initializers/stripe.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb index 1a2bcfae80..d1da4d90b2 100644 --- a/config/initializers/stripe.rb +++ b/config/initializers/stripe.rb @@ -1,2 +1,3 @@ # -*- encoding : utf-8 -*- Stripe.api_key = AlaveteliConfiguration.stripe_secret_key +Stripe.api_version = '2017-01-27' From e5dc3861aa670a68d13b7cff8cd0516577112a4f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 16 Jul 2019 12:34:30 +0100 Subject: [PATCH 058/114] Bump stripe gem from 3.4.1 to 3.29.0 Bumps [stripe](https://github.com/stripe/stripe-ruby) from 3.4.1 to 3.29.0 - [Release notes](https://github.com/stripe/stripe-ruby/releases?after=v3.30.0) - [Changelog](https://github.com/stripe/stripe-ruby/blob/master/CHANGELOG.md#3290---2018-10-30) - [Commits](https://github.com/stripe/stripe-ruby/compare/v3.4.1...v3.29.0) --- Gemfile | 2 +- Gemfile.lock | 6 +++--- Gemfile.rails_next.lock | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index 358a4094c0..c31cba267c 100644 --- a/Gemfile +++ b/Gemfile @@ -122,7 +122,7 @@ gem 'rubyzip', '~> 1.2.2' gem 'secure_headers', '~> 3.6.0' gem 'statistics2', '~> 0.54' gem 'strip_attributes', :git => 'https://github.com/mysociety/strip_attributes.git', :ref => 'c1c14da' -gem 'stripe', '~> 3.4.1' +gem 'stripe', '~> 3.29.0' gem 'syslog_protocol', '~> 0.9.0' gem 'thin', '~> 1.5.0', '< 1.6.0' gem 'vpim', '~> 13.11.11' diff --git a/Gemfile.lock b/Gemfile.lock index 4b998dc284..0cb0f556ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -169,7 +169,7 @@ GEM railties (>= 3.0.0) fancybox-rails (0.3.1) railties (>= 3.1.0) - faraday (0.15.2) + faraday (0.15.4) multipart-post (>= 1.2, < 3) fast_gettext (1.1.2) ffi (1.9.25) @@ -372,7 +372,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) statistics2 (0.54) - stripe (3.4.1) + stripe (3.29.0) faraday (~> 0.10) stripe-ruby-mock (2.5.6) dante (>= 0.2.0) @@ -497,7 +497,7 @@ DEPENDENCIES secure_headers (~> 3.6.0) statistics2 (~> 0.54) strip_attributes! - stripe (~> 3.4.1) + stripe (~> 3.29.0) stripe-ruby-mock (~> 2.5.4, < 2.5.7) syslog_protocol (~> 0.9.0) therubyracer (~> 0.12.0) diff --git a/Gemfile.rails_next.lock b/Gemfile.rails_next.lock index 4be98e758b..53f185fcf7 100644 --- a/Gemfile.rails_next.lock +++ b/Gemfile.rails_next.lock @@ -169,7 +169,7 @@ GEM railties (>= 3.0.0) fancybox-rails (0.3.1) railties (>= 3.1.0) - faraday (0.15.2) + faraday (0.15.4) multipart-post (>= 1.2, < 3) fast_gettext (1.1.2) ffi (1.9.25) @@ -372,7 +372,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) statistics2 (0.54) - stripe (3.4.1) + stripe (3.29.0) faraday (~> 0.10) stripe-ruby-mock (2.5.6) dante (>= 0.2.0) @@ -497,7 +497,7 @@ DEPENDENCIES secure_headers (~> 3.6.0) statistics2 (~> 0.54) strip_attributes! - stripe (~> 3.4.1) + stripe (~> 3.29.0) stripe-ruby-mock (~> 2.5.4, < 2.5.7) syslog_protocol (~> 0.9.0) therubyracer (~> 0.12.0) From 7adee9ed63fdb7629d4022760cbf3c83adbec444 Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 17 Jul 2019 20:04:21 +0100 Subject: [PATCH 059/114] Refactor ActiveRecord query to use named parameter --- app/controllers/admin_user_controller.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb index 903a5da229..fbf4bc5b2a 100644 --- a/app/controllers/admin_user_controller.rb +++ b/app/controllers/admin_user_controller.rb @@ -28,8 +28,11 @@ def index @sort_options.key?(params[:sort_order]) ? params[:sort_order] : 'name_asc' users = if @query.present? - User.where(["lower(users.name) LIKE lower('%'||?||'%') OR " \ - "lower(users.email) LIKE lower('%'||?||'%')", @query, @query]) + User.where( + "lower(users.name) LIKE lower('%'||:query||'%') OR " \ + "lower(users.email) LIKE lower('%'||:query||'%')" + query: @query + ) else User end From 5f26602a704028e71bcbef32ca3866e4a611840f Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 17 Jul 2019 20:04:21 +0100 Subject: [PATCH 060/114] Add admin user searching for about me text --- app/controllers/admin_user_controller.rb | 3 ++- app/views/admin_user/index.html.erb | 2 +- spec/controllers/admin_user_controller_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb index fbf4bc5b2a..0a2af39666 100644 --- a/app/controllers/admin_user_controller.rb +++ b/app/controllers/admin_user_controller.rb @@ -30,7 +30,8 @@ def index users = if @query.present? User.where( "lower(users.name) LIKE lower('%'||:query||'%') OR " \ - "lower(users.email) LIKE lower('%'||:query||'%')" + "lower(users.email) LIKE lower('%'||:query||'%') OR " \ + "lower(users.about_me) LIKE lower('%'||:query||'%')", query: @query ) else diff --git a/app/views/admin_user/index.html.erb b/app/views/admin_user/index.html.erb index c37fa649d0..8feb81b194 100644 --- a/app/views/admin_user/index.html.erb +++ b/app/views/admin_user/index.html.erb @@ -10,7 +10,7 @@
<%= text_field_tag 'query', params[:query], { :size => 30, :class => "input-large search-query"} %> <%= hidden_field_tag 'sort_order', @sort_order %> - <%= submit_tag "Search", :class => "btn" %> (substring search, names and emails) + <%= submit_tag "Search", :class => "btn" %> (substring search, names, emails and about me) <%= link_to 'Banned users', banned_admin_users_path, :class => "btn btn-info" %>
diff --git a/spec/controllers/admin_user_controller_spec.rb b/spec/controllers/admin_user_controller_spec.rb index d969a4d724..f943426e7e 100644 --- a/spec/controllers/admin_user_controller_spec.rb +++ b/spec/controllers/admin_user_controller_spec.rb @@ -103,6 +103,12 @@ expect(assigns[:admin_users]).to include(user) end + it 'will search the about me text' do + user = FactoryBot.create(:user, about_me: 'http://example.com') + get :index, params: { query: 'http' } + expect(assigns[:admin_users]).to include(user) + end + it 'searches and sorts the records' do User.destroy_all u1 = FactoryBot.create(:user, :name => 'Alice Smith') From 851fc5980cc2d08e3ad7fd2a98e93c8bb10081e7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 22 Jul 2019 09:54:29 +0100 Subject: [PATCH 061/114] Make send-pro-metrics-report executable Can't be called directly if its not executable. Fixes https://github.com/mysociety/alaveteli/issues/5312 --- script/send-pro-metrics-report | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 script/send-pro-metrics-report diff --git a/script/send-pro-metrics-report b/script/send-pro-metrics-report old mode 100644 new mode 100755 From 4fe726d4855a378d9df428a32814f0b790eaf6f5 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 23 Jul 2019 09:56:37 +0100 Subject: [PATCH 062/114] Call BigDecimal() instead of the BigDecimal.new() BigDecimal.new() is deprecated and raises warning messages in Ruby 2.5+ warning: BigDecimal.new is deprecated; use BigDecimal() method instead --- app/models/alaveteli_pro/subscription_with_discount.rb | 4 ++-- app/models/alaveteli_pro/with_tax.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/alaveteli_pro/subscription_with_discount.rb b/app/models/alaveteli_pro/subscription_with_discount.rb index d797e594fd..06fece0be8 100644 --- a/app/models/alaveteli_pro/subscription_with_discount.rb +++ b/app/models/alaveteli_pro/subscription_with_discount.rb @@ -27,7 +27,7 @@ def initialize(subscription) end def amount - net = BigDecimal.new((original_amount * 0.01), 0).round(2) + net = BigDecimal((original_amount * 0.01), 0).round(2) net = net - reduction(net) (net * 100).floor end @@ -74,7 +74,7 @@ def reduction(net) def coupon_reduction(net) if coupon.amount_off - BigDecimal.new((coupon.amount_off * 0.01), 0).round(2) + BigDecimal((coupon.amount_off * 0.01), 0).round(2) else (net * coupon.percent_off / 100) end diff --git a/app/models/alaveteli_pro/with_tax.rb b/app/models/alaveteli_pro/with_tax.rb index 919da20082..11d117b7ca 100644 --- a/app/models/alaveteli_pro/with_tax.rb +++ b/app/models/alaveteli_pro/with_tax.rb @@ -14,9 +14,9 @@ class AlaveteliPro::WithTax < SimpleDelegator TAX_RATE = BigDecimal('0.20').freeze def amount_with_tax - # Need to use BigDecimal.new here because SimpleDelegator is forwarding + # Need to use BigDecimal() here because SimpleDelegator is forwarding # `#BigDecimal` to `#amount` in Ruby 2.0. - net = BigDecimal.new(amount * 0.01, 0).round(2) + net = BigDecimal(amount * 0.01, 0).round(2) vat = (net * TAX_RATE).round(2) gross = net + vat (gross * 100).floor From 1cf16bfefbf42e60c9372bf582c37642c9e8f06f Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Fri, 12 Jul 2019 11:38:11 +0100 Subject: [PATCH 063/114] Mark up pricing page strings for translation --- app/views/alaveteli_pro/plans/index.html.erb | 75 +++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/app/views/alaveteli_pro/plans/index.html.erb b/app/views/alaveteli_pro/plans/index.html.erb index 103c04e1cb..2bafea4a59 100644 --- a/app/views/alaveteli_pro/plans/index.html.erb +++ b/app/views/alaveteli_pro/plans/index.html.erb @@ -1,22 +1,22 @@ -

Pricing

+

<%= _('Pricing') %>

-

Professional

-

For journalists, academics and power users

+

<%= _('Professional') %>

+

<%= _('For journalists, academics and power users') %>

£10 per user, per month

-

Introductory Pricing

+

<%= _('Introductory Pricing') %>

-

Featuring

+

<%= _('Featuring') %>

    -
  • Public requests for information
  • -
  • Private requests for information
  • -
  • Dashboard and workflow features
  • -
  • Friendly support
  • +
  • <%= _('Public requests for information') %>
  • +
  • <%= _('Private requests for information') %>
  • +
  • <%= _('Dashboard and workflow features') %>
  • +
  • <%= _('Friendly support') %>
<%= link_to _('Sign up'), plan_path('pro'), :class => 'button button-pop' %>
@@ -25,72 +25,77 @@

- Don't worry – <%= link_to 'our free accounts', signin_path %> are still available and always will be. + <%= _('Don’t worry – our free accounts are still available and always will be.', + signup_link: signin_path) %>

-

New to Professional – Batch

-

Make a request to multiple authorities and manage the responses.

+

<%= _('New to Professional – Batch') %>

+

<%= _('Make a request to multiple authorities and manage the responses.') %>

-

WhatDoTheyKnowPro

-

An all-in-one FOI toolkit for journalists, activists and campaigners

+

<%= AlaveteliConfiguration.pro_site_name %>

+

<%= _('An all-in-one FOI toolkit for journalists, activists and campaigners') %>

    -
  • Keep requests and responses private while you work on your story
  • -
  • A powerful private dashboard: track and manage your FOI projects
  • -
  • A super-smart to-do list: follow the progress of your requests
  • -
  • Action alerts: know when it’s time to take the next step
  • -
  • Daily summary emails to keep your inbox clean
  • -
  • Save as draft to get back to it later
  • +
  • <%= _('Keep requests and responses private while you work on your story') %>
  • +
  • <%= _('A powerful private dashboard: track and manage your FOI projects') %>
  • +
  • <%= _('A super-smart to-do list: follow the progress of your requests') %>
  • +
  • <%= _('Action alerts: know when it’s time to take the next step') %>
  • +
  • <%= _('Daily summary emails to keep your inbox clean') %>
  • +
  • <%= _('Save as draft to get back to it later') %>
-

Plus, all the power of WhatDoTheyKnow

-

WhatDoTheyKnowPro runs on the UK’s best-known FOI service

+

<%= _('Plus, all the power of {{site_name}}', site_name: site_name) %>

+

<%= _('{{pro_site_name}} runs on the UK’s ' \ + 'best-known FOI service', + pro_site_name: AlaveteliConfiguration.pro_site_name) %>

    -
  • Up-to-date database of contact details for 20,000 authorities
  • -
  • A searchable archive of Freedom of Information requests
  • -
  • Delivery verification for proof of receipt
  • -
  • A permanent, searchable, public record of your request and the responses
  • -
  • Streamlined process for requesting internal reviews
  • +
  • <%= _('Up-to-date database of ' \ + 'contact details for {{authority_count}} authorities', + authority_count: PublicBody.is_requestable.count) %>
  • +
  • <%= _('A searchable archive of Freedom of Information requests') %>
  • +
  • <%= _('Delivery verification for proof of receipt') %>
  • +
  • <%= _('A permanent, searchable, public record of your request and the responses') %>
  • +
  • <%= _('Streamlined process for requesting internal reviews') %>
-

Batch

+

<%= _('Batch') %>

    -
  • Make a request to multiple authorities: select authorities at the click of a button
  • -
  • Manage large volumes of responses: easily keep track of the status of each request
  • -
  • Get regular updates as the responses come in — without overwhelming your inbox
  • +
  • <%= _('Make a request to multiple authorities: select authorities at the click of a button') %>
  • +
  • <%= _('Manage large volumes of responses: easily keep track of the status of each request') %>
  • +
  • <%= _('Get regular updates as the responses come in — without overwhelming your inbox') %>
<%= link_to _('Sign up'), plan_path('pro'), :class => 'button' %> From b8c2ccec385d4499e97c304fb413aa9db15c8f78 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Mon, 15 Jul 2019 09:52:19 +0100 Subject: [PATCH 064/114] Allow CurrencyHelper#format_currency to suppress trailing zeros Uses the money gem's `:no_cents_if_whole` option for this https://www.rubydoc.info/gems/money/Money/Formatter --- app/helpers/currency_helper.rb | 5 +++-- spec/helpers/currency_helper_spec.rb | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/app/helpers/currency_helper.rb b/app/helpers/currency_helper.rb index 5bdc802f15..01f9be6db2 100644 --- a/app/helpers/currency_helper.rb +++ b/app/helpers/currency_helper.rb @@ -1,5 +1,6 @@ module CurrencyHelper - def format_currency(amount) - Money.new(amount, AlaveteliConfiguration.iso_currency_code).format + def format_currency(amount, no_cents_if_whole: false) + Money.new(amount, AlaveteliConfiguration.iso_currency_code). + format(no_cents_if_whole: no_cents_if_whole) end end diff --git a/spec/helpers/currency_helper_spec.rb b/spec/helpers/currency_helper_spec.rb index c30e01e518..f4552f7ab8 100644 --- a/spec/helpers/currency_helper_spec.rb +++ b/spec/helpers/currency_helper_spec.rb @@ -4,10 +4,12 @@ include CurrencyHelper describe '#format_currency' do - - it 'format amount in the configured currency' do + before do allow(AlaveteliConfiguration).to receive(:iso_currency_code). and_return('GBP') + end + + it 'formats the amount in the configured currency' do expect(format_currency(123456)).to eq('£1,234.56') allow(AlaveteliConfiguration).to receive(:iso_currency_code). @@ -15,6 +17,25 @@ expect(format_currency(123456)).to eq('1.234,56 kn') end + it 'shows currency sub-units by default' do + expect(format_currency(1500)).to eq('£15.00') + end + + context 'when asked to show the amount without trailing zeros' do + it 'does not show the trailing sub-unit amount when it is 00' do + expect(format_currency(123400, no_cents_if_whole: true)).to eq('£1,234') + end + + it 'does not rely on the UK currency format' do + allow(AlaveteliConfiguration).to receive(:iso_currency_code). + and_return('EUR') + expect(format_currency(123400, no_cents_if_whole: true)).to eq('€1.234') + end + + it 'still shows the sub-unit value if it is a non-zero amount' do + expect(format_currency(1499, no_cents_if_whole: true)).to eq('£14.99') + end + end end end From 719e0b814d0323c3c2dab51a593dd5196db445c6 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Mon, 15 Jul 2019 09:58:26 +0100 Subject: [PATCH 065/114] Get the plan price from the default Stripe plan on the pricing page Assumes that the default plan will always have an id of 'pro' --- .../alaveteli_pro/plans_controller.rb | 3 ++ app/views/alaveteli_pro/plans/index.html.erb | 8 +++- .../alaveteli_pro/plans_controller_spec.rb | 3 ++ .../plans/index.html.erb_spec.rb | 37 +++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 spec/views/alaveteli_pro/plans/index.html.erb_spec.rb diff --git a/app/controllers/alaveteli_pro/plans_controller.rb b/app/controllers/alaveteli_pro/plans_controller.rb index 098aa8ed05..978a333330 100644 --- a/app/controllers/alaveteli_pro/plans_controller.rb +++ b/app/controllers/alaveteli_pro/plans_controller.rb @@ -6,6 +6,9 @@ class AlaveteliPro::PlansController < AlaveteliPro::BaseController before_action :authenticate, :check_existing_subscription, only: [:show] def index + default_plan_name = add_stripe_namespace('pro') + stripe_plan = Stripe::Plan.retrieve(default_plan_name) + @plan = AlaveteliPro::WithTax.new(stripe_plan) end def show diff --git a/app/views/alaveteli_pro/plans/index.html.erb b/app/views/alaveteli_pro/plans/index.html.erb index 2bafea4a59..9db1beeeec 100644 --- a/app/views/alaveteli_pro/plans/index.html.erb +++ b/app/views/alaveteli_pro/plans/index.html.erb @@ -6,7 +6,13 @@

<%= _('Professional') %>

<%= _('For journalists, academics and power users') %>

-

£10 per user, per month

+

+ <%= _('{{monthly_price}} ' \ + 'per user, per month', + monthly_price: format_currency( + @plan.amount_with_tax, + no_cents_if_whole: true)) %> +

<%= _('Introductory Pricing') %>

diff --git a/spec/controllers/alaveteli_pro/plans_controller_spec.rb b/spec/controllers/alaveteli_pro/plans_controller_spec.rb index 4d317b5237..4c67a04cde 100644 --- a/spec/controllers/alaveteli_pro/plans_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/plans_controller_spec.rb @@ -29,6 +29,9 @@ expect(assigns(:in_pro_area)).to be true end + it 'uses the default plan for pricing info' do + expect(assigns(:plan)).to eq(pro_plan) + end end describe 'GET #show' do diff --git a/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb b/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb new file mode 100644 index 0000000000..455a2637f2 --- /dev/null +++ b/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'alaveteli_pro/plans/index.html.erb' do + before { StripeMock.start } + after { StripeMock.stop } + let(:stripe_helper) { StripeMock.create_test_helper } + let(:plan_with_tax) { AlaveteliPro::WithTax.new(stripe_plan) } + let(:cents_price) { 880 } + + let(:stripe_plan) do + stripe_helper.create_plan(id: 'pro', amount: cents_price) + end + + before do + allow(AlaveteliConfiguration).to receive(:iso_currency_code). + and_return('GBP') + assign :plan, plan_with_tax + end + + context 'the price does not have a cents value' do + it 'shows the price without trailing cents' do + render + expect(rendered). + to have_css('span', class: 'price-label__amount', text: '£10') + end + end + + context 'the price has a cents value' do + let(:cents_price) { 832 } + + it 'shows the whole amount including cents' do + render + expect(rendered). + to have_css('span', class: 'price-label__amount', text: '£9.98') + end + end +end From 2ac1e26bab20eb17b98c1d5e3199a6493f0019c6 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 24 Jul 2019 11:57:37 +0100 Subject: [PATCH 066/114] Set the pro_site_name for the pricing page in the controller This allows sites that would like to use HTML markup in the site name on the marketing page to override the controller method rather than copying the entire page template --- app/controllers/alaveteli_pro/plans_controller.rb | 1 + app/views/alaveteli_pro/plans/index.html.erb | 4 ++-- spec/controllers/alaveteli_pro/plans_controller_spec.rb | 4 ++++ spec/views/alaveteli_pro/plans/index.html.erb_spec.rb | 7 +++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/controllers/alaveteli_pro/plans_controller.rb b/app/controllers/alaveteli_pro/plans_controller.rb index 978a333330..d373f0b51e 100644 --- a/app/controllers/alaveteli_pro/plans_controller.rb +++ b/app/controllers/alaveteli_pro/plans_controller.rb @@ -9,6 +9,7 @@ def index default_plan_name = add_stripe_namespace('pro') stripe_plan = Stripe::Plan.retrieve(default_plan_name) @plan = AlaveteliPro::WithTax.new(stripe_plan) + @pro_site_name = AlaveteliConfiguration.pro_site_name end def show diff --git a/app/views/alaveteli_pro/plans/index.html.erb b/app/views/alaveteli_pro/plans/index.html.erb index 9db1beeeec..fe22861e56 100644 --- a/app/views/alaveteli_pro/plans/index.html.erb +++ b/app/views/alaveteli_pro/plans/index.html.erb @@ -42,7 +42,7 @@
-

<%= AlaveteliConfiguration.pro_site_name %>

+

<%= @pro_site_name %>

<%= _('An all-in-one FOI toolkit for journalists, activists and campaigners') %>

@@ -68,7 +68,7 @@

<%= _('Plus, all the power of {{site_name}}', site_name: site_name) %>

<%= _('{{pro_site_name}} runs on the UK’s ' \ 'best-known FOI service', - pro_site_name: AlaveteliConfiguration.pro_site_name) %>

+ pro_site_name: @pro_site_name) %>

diff --git a/spec/controllers/alaveteli_pro/plans_controller_spec.rb b/spec/controllers/alaveteli_pro/plans_controller_spec.rb index 4c67a04cde..c103964e4d 100644 --- a/spec/controllers/alaveteli_pro/plans_controller_spec.rb +++ b/spec/controllers/alaveteli_pro/plans_controller_spec.rb @@ -29,6 +29,10 @@ expect(assigns(:in_pro_area)).to be true end + it 'sets pro_site_name' do + expect(assigns(:pro_site_name)).to eq AlaveteliConfiguration.pro_site_name + end + it 'uses the default plan for pricing info' do expect(assigns(:plan)).to eq(pro_plan) end diff --git a/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb b/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb index 455a2637f2..ebd2527cf0 100644 --- a/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb +++ b/spec/views/alaveteli_pro/plans/index.html.erb_spec.rb @@ -15,6 +15,13 @@ allow(AlaveteliConfiguration).to receive(:iso_currency_code). and_return('GBP') assign :plan, plan_with_tax + assign :pro_site_name, 'AlaveteliPro' + end + + it 'uses the pro site name assigned by the controller' do + render + expect(rendered). + to have_css('h2', text: assigns[:pro_site_name]) end context 'the price does not have a cents value' do From 5c10f3aea4f1ad09c1a13543f10eeb81c6635602 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 24 Jul 2019 12:17:28 +0100 Subject: [PATCH 067/114] Mark pro_site_name as html_safe Otherwise an override that uses HTML markup will escape the tags --- app/views/alaveteli_pro/plans/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/alaveteli_pro/plans/index.html.erb b/app/views/alaveteli_pro/plans/index.html.erb index fe22861e56..17334556c3 100644 --- a/app/views/alaveteli_pro/plans/index.html.erb +++ b/app/views/alaveteli_pro/plans/index.html.erb @@ -42,7 +42,7 @@
-

<%= @pro_site_name %>

+

<%= @pro_site_name.html_safe %>

<%= _('An all-in-one FOI toolkit for journalists, activists and campaigners') %>

@@ -68,7 +68,7 @@

<%= _('Plus, all the power of {{site_name}}', site_name: site_name) %>

<%= _('{{pro_site_name}} runs on the UK’s ' \ 'best-known FOI service', - pro_site_name: @pro_site_name) %>

+ pro_site_name: @pro_site_name.html_safe) %>

From b185a9968f75a8d53e78cd0f5976311a45fd0233 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 17 Jul 2019 09:51:45 +0100 Subject: [PATCH 068/114] Add a rake task to create the Stripe webhook endpoint --- config/initializers/alaveteli.rb | 1 + lib/alaveteli_pro/webhook_endpoints.rb | 38 +++++++++++++++++++ lib/tasks/stripe.rake | 23 +++++++++++ .../alaveteli_pro/webhook_endpoints_spec.rb | 25 ++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 lib/alaveteli_pro/webhook_endpoints.rb create mode 100644 lib/tasks/stripe.rake create mode 100644 spec/lib/alaveteli_pro/webhook_endpoints_spec.rb diff --git a/config/initializers/alaveteli.rb b/config/initializers/alaveteli.rb index b0ea880d45..54866feaa9 100644 --- a/config/initializers/alaveteli.rb +++ b/config/initializers/alaveteli.rb @@ -65,6 +65,7 @@ require 'alaveteli_mail_poller' require 'safe_redirect' require 'alaveteli_pro/metrics_report' +require 'alaveteli_pro/webhook_endpoints' AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales, AlaveteliConfiguration::default_locale) diff --git a/lib/alaveteli_pro/webhook_endpoints.rb b/lib/alaveteli_pro/webhook_endpoints.rb new file mode 100644 index 0000000000..3fe14cba83 --- /dev/null +++ b/lib/alaveteli_pro/webhook_endpoints.rb @@ -0,0 +1,38 @@ +module AlaveteliPro + ## + # A class for working with the Stripe WebhookEndpoints API + class WebhookEndpoints + ## + # Calculates the URL of the Stripe webhook endpoint for the install + def self.webhook_endpoint_url + options = { + host: AlaveteliConfiguration.domain, + protocol: AlaveteliConfiguration.force_ssl ? 'https' : 'http', + locale: false + } + + Rails.application.routes.url_helpers. + pro_subscriptions_stripe_webhook_url(options) + end + + ## + # Helper method to juggle retrieving all the endpoints from the API + # (not that we're expecting there to be 100s of endpoints to navigate) + def self.retrieve_all_endpoints_data + list = retrieve_endpoints + data = list.data + while list.has_more + list = retrieve_endpoints(data.last.id) + data += list.data + end + data + end + + ## + # Simple wrapper for Stripe's list method to pull down the maximum + # allowed number of endpoints in a single call + def self.retrieve_endpoints(starting_after = nil) + Stripe::WebhookEndpoint.list(limit: 100, starting_after: starting_after) + end + end +end diff --git a/lib/tasks/stripe.rake b/lib/tasks/stripe.rake new file mode 100644 index 0000000000..e0f66d99b5 --- /dev/null +++ b/lib/tasks/stripe.rake @@ -0,0 +1,23 @@ +namespace :stripe do + desc "Create the Stripe webhook endpoint" + task create_webhook_endpoint: :environment do + endpoint = AlaveteliPro::WebhookEndpoints.webhook_endpoint_url + + # Find all hooks that POST to our Alaveteli install + hooks = AlaveteliPro::WebhookEndpoints.retrieve_all_endpoints_data. + select { |hook| hook.url == endpoint } + + # If there's no hook that matches our requirements, create it. + if hooks.empty? + Stripe::WebhookEndpoint.create(url: endpoint, + api_version: Stripe.api_version, + enabled_events: [ + 'customer.subscription.deleted', + 'invoice.payment_succeeded', + 'invoice.payment_failed', + 'customer.subscription.updated' + ] + ) + end + end +end diff --git a/spec/lib/alaveteli_pro/webhook_endpoints_spec.rb b/spec/lib/alaveteli_pro/webhook_endpoints_spec.rb new file mode 100644 index 0000000000..c450b88e24 --- /dev/null +++ b/spec/lib/alaveteli_pro/webhook_endpoints_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' +require 'stripe_mock' + +describe AlaveteliPro::WebhookEndpoints do + before { StripeMock.start } + after { StripeMock.stop } + let(:stripe_helper) { StripeMock.create_test_helper } + + describe '.webhook_endpoint_url' do + subject { described_class.webhook_endpoint_url } + + it { is_expected.to match('test.host/pro/subscriptions/stripe-webhook') } + + context 'https is disabled' do + it { is_expected.to match(/^http:/) } + end + + context 'https is enabled' do + it 'uses the http protocol' do + allow(AlaveteliConfiguration).to receive(:force_ssl).and_return(true) + expect(subject).to match(/^https:/) + end + end + end +end From 766ad8cc272f58e83a65807e8b475f7154469981 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Wed, 17 Jul 2019 09:56:52 +0100 Subject: [PATCH 069/114] Add rake task output via stderr --- lib/tasks/stripe.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/tasks/stripe.rake b/lib/tasks/stripe.rake index e0f66d99b5..fcd031cc4c 100644 --- a/lib/tasks/stripe.rake +++ b/lib/tasks/stripe.rake @@ -18,6 +18,9 @@ namespace :stripe do 'customer.subscription.updated' ] ) + $stderr.puts 'Webhook endpoint successfully created!' + else + $stderr.puts 'Webhook endpoint already exists, stopping' end end end From 8421cd04ca58f97f5d1ccdf0abe8b1b10134c443 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 23 Jul 2019 11:07:37 +0100 Subject: [PATCH 070/114] Set the webhook events to enable in the Stripe initializer --- config/initializers/stripe.rb | 11 +++++++++++ lib/tasks/stripe.rake | 9 ++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb index d1da4d90b2..843680a8ef 100644 --- a/config/initializers/stripe.rb +++ b/config/initializers/stripe.rb @@ -1,3 +1,14 @@ # -*- encoding : utf-8 -*- Stripe.api_key = AlaveteliConfiguration.stripe_secret_key Stripe.api_version = '2017-01-27' + +module Stripe + ## + # An array of events that we want to enable for our webhook endpoint + def self.webhook_events + %w( + customer.subscription.deleted invoice.payment_succeeded + invoice.payment_failed customer.subscription.updated + ) + end +end diff --git a/lib/tasks/stripe.rake b/lib/tasks/stripe.rake index fcd031cc4c..ae5f299154 100644 --- a/lib/tasks/stripe.rake +++ b/lib/tasks/stripe.rake @@ -11,13 +11,8 @@ namespace :stripe do if hooks.empty? Stripe::WebhookEndpoint.create(url: endpoint, api_version: Stripe.api_version, - enabled_events: [ - 'customer.subscription.deleted', - 'invoice.payment_succeeded', - 'invoice.payment_failed', - 'customer.subscription.updated' - ] - ) + enabled_events: Stripe.webhook_events) + $stderr.puts 'Webhook endpoint successfully created!' else $stderr.puts 'Webhook endpoint already exists, stopping' From 496e28fb458bbc8dad820ca803e8743c3cd0d14a Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Tue, 23 Jul 2019 11:08:13 +0100 Subject: [PATCH 071/114] Return the webhook signing secret after creating the webhook --- lib/tasks/stripe.rake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/tasks/stripe.rake b/lib/tasks/stripe.rake index ae5f299154..3b669bd769 100644 --- a/lib/tasks/stripe.rake +++ b/lib/tasks/stripe.rake @@ -9,11 +9,14 @@ namespace :stripe do # If there's no hook that matches our requirements, create it. if hooks.empty? - Stripe::WebhookEndpoint.create(url: endpoint, - api_version: Stripe.api_version, - enabled_events: Stripe.webhook_events) + ret = + Stripe::WebhookEndpoint.create(url: endpoint, + api_version: Stripe.api_version, + enabled_events: Stripe.webhook_events) $stderr.puts 'Webhook endpoint successfully created!' + $stderr.puts 'Add this line to your general.yml config file:' + $stderr.puts " STRIPE_WEBHOOK_SECRET: #{ret.secret}" else $stderr.puts 'Webhook endpoint already exists, stopping' end From 14f9820c248a37d752fb68c9b6eb2c2a80123d61 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Thu, 25 Jul 2019 12:36:50 +0100 Subject: [PATCH 072/114] Update changelog --- doc/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 69ad3def1f..85042288c3 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -2,6 +2,7 @@ ## Highlighted Features +* Add new rake task to create the Stripe webhook endpoint (Liz Conlan) * Send weekly metrics email to the Pro Admin team (Liz Conlan, Gareth Rees) * Improve error handling when sending request-related emails (initial request mails and followups) - failed messages are captured and a send_error event is From 3b0d888d7d53b0c3d9abce42b4158412e09bf88c Mon Sep 17 00:00:00 2001 From: Graeme Porteous Date: Wed, 24 Jul 2019 15:01:50 +0100 Subject: [PATCH 073/114] Add recent changes from plans/index view See: https://github.com/mysociety/alaveteli/pull/5294 --- .../alaveteli_pro/account_request_controller.rb | 1 + .../alaveteli_pro/account_request/index.html.erb | 11 ++++++----- .../alaveteli_pro/account_request_controller_spec.rb | 5 +++++ .../account_request/index.html.erb_spec.rb | 4 ++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/controllers/alaveteli_pro/account_request_controller.rb b/app/controllers/alaveteli_pro/account_request_controller.rb index 48e98f07dd..4074f738fb 100644 --- a/app/controllers/alaveteli_pro/account_request_controller.rb +++ b/app/controllers/alaveteli_pro/account_request_controller.rb @@ -5,6 +5,7 @@ class AlaveteliPro::AccountRequestController < ApplicationController def index @public_beta = true + @pro_site_name = AlaveteliConfiguration.pro_site_name end def new diff --git a/app/views/alaveteli_pro/account_request/index.html.erb b/app/views/alaveteli_pro/account_request/index.html.erb index f5fb598808..d166669544 100644 --- a/app/views/alaveteli_pro/account_request/index.html.erb +++ b/app/views/alaveteli_pro/account_request/index.html.erb @@ -3,7 +3,7 @@

<%= _('{{pro_site_name}} is a powerful, fully-featured FOI toolkit ' \ 'for journalists', - pro_site_name: AlaveteliConfiguration.pro_site_name) %> + pro_site_name: @pro_site_name.html_safe) %>

<%= _('Everything you need to keep on top of complex FOI-driven ' \ @@ -23,7 +23,7 @@

-

<%= AlaveteliConfiguration.pro_site_name %>

+

<%= @pro_site_name.html_safe %>

<%= _('An all-in-one FOI toolkit for journalists, activists and ' \ 'campaigners') %>

@@ -73,14 +73,15 @@

<%=_('Plus, all the power of {{site_name}}', - site_name: AlaveteliConfiguration.site_name) %>

+ site_name: site_name) %>

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�!>zE60kl7yB90s@8*AQb6H5hWx6lF&j2 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 M64~9YaliDx0QIpwxc~qF literal 0 HcmV?d00001 diff --git a/app/assets/images/alaveteli-pro/screenshot-embargo.jpg b/app/assets/images/alaveteli-pro/screenshot-embargo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05deec98a15a4d5db9fd0d4bf85ddd804081a8fe GIT binary patch literal 11650 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 Date: Tue, 2 Jul 2019 13:34:53 +0100 Subject: [PATCH 054/114] Remove dangerous upgrade note This task was renamed to `destroy_and_rebuild_index` in c452935fea2d4da21d4d204d6769790e34796427. --- doc/CHANGES.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 98988d6661..070069c93e 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -1412,10 +1412,6 @@ There are some database structure updates so remember to rake db:migrate httpd.conf-example` and `config/nginx.conf.example`). * Install the `geoip-database-contrib` package to automatically fetch latest geoip databases. -* To make requests searchable based on their public body's tags you'll need to - reindex Xapian. To make this quicker you can selectively reindex just the - model and new term by running - `bundle exec rake xapian:rebuild_index models="InfoRequestEvent" terms="X"` * To update events to use the new 'hide' event type you need to run `rake temp:update_hide_event_type` * If you've added Javascript to overriden view templates, you should wrap it From b20f0c9f8213a8ac167314bde1202679f2004b29 Mon Sep 17 00:00:00 2001 From: Liz Conlan Date: Mon, 15 Jul 2019 13:37:18 +0100 Subject: [PATCH 055/114] Add missing translation markup for the Pro plan page --- app/views/alaveteli_pro/plans/show.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/alaveteli_pro/plans/show.html.erb b/app/views/alaveteli_pro/plans/show.html.erb index 802cbb3ec9..24a55b96e6 100644 --- a/app/views/alaveteli_pro/plans/show.html.erb +++ b/app/views/alaveteli_pro/plans/show.html.erb @@ -39,7 +39,7 @@