Updated

app/models/archived / petition.rb

F
393 lines of codes
62 methods
4.5 complexity/method
23 churn
276.4 complexity
83 duplications
require 'textacular/searchable' require_dependency 'archived' module Archived class Petition < ActiveRecord::Base
  1. Archived::Petition assumes too much for instance variable '@_signatures_by_constituency'
  2. Archived::Petition assumes too much for instance variable '@_signatures_by_country'
  3. Archived::Petition has no descriptive comment
  4. Archived::Petition has 9 constants
  5. Archived::Petition has at least 62 methods
STOPPED_STATE = 'stopped' CLOSED_STATE = 'closed' HIDDEN_STATE = 'hidden' REJECTED_STATE = 'rejected' STATES = [STOPPED_STATE, CLOSED_STATE, HIDDEN_STATE, REJECTED_STATE] PUBLISHED_STATES = [CLOSED_STATE] VISIBLE_STATES = [CLOSED_STATE, REJECTED_STATE] MODERATED_STATES = [CLOSED_STATE, HIDDEN_STATE, REJECTED_STATE] DEBATABLE_STATES = [CLOSED_STATE] belongs_to :parliament, inverse_of: :petitions, required: true belongs_to :locked_by, class_name: 'AdminUser' has_one :creator, -> { creator }, class_name: "Signature" has_one :debate_outcome, dependent: :destroy has_one :government_response, dependent: :destroy has_one :note, dependent: :destroy has_one :rejection, dependent: :destroy has_many :emails, :dependent => :destroy has_many :signatures has_many :sponsors, -> { sponsors }, class_name: "Signature" validates :action, presence: true, length: { maximum: 150 } validates :background, length: { maximum: 300 }, allow_blank: true validates :additional_details, length: { maximum: 1000 }, allow_blank: true validates :state, presence: true, inclusion: STATES validates :closed_at, presence: true, if: :closed? before_save :update_debate_state, if: :scheduled_debate_date_changed? extend Searchable(:action, :background, :additional_details) include Browseable, Taggable filter :parliament facet :all, -> { visible.by_most_signatures } facet :awaiting_response, -> { awaiting_response.by_waiting_for_response_longest } facet :awaiting_debate_date, -> { awaiting_debate_date.by_waiting_for_debate_longest } facet :with_debate_outcome, -> { with_debate_outcome.by_most_recent_debate_outcome } facet :with_debated_outcome, -> { with_debated_outcome.by_most_recent_debate_outcome } facet :published, -> { published.by_most_signatures } facet :stopped, -> { stopped.by_most_signatures } facet :closed, -> { closed.by_most_signatures } facet :rejected, -> { rejected.by_most_signatures } facet :hidden, -> { hidden.by_most_recent } facet :with_response, -> { with_response.by_most_signatures } facet :debated, -> { debated.by_most_recent_debate_outcome } facet :not_debated, -> { not_debated.by_most_recent_debate_outcome } facet :by_most_signatures, -> { by_most_signatures } facet :by_created_at, -> { by_created_at } facet :in_debate_queue, -> { in_debate_queue.by_waiting_for_debate_longest } default_scope { preload(:parliament) } delegate :threshold_for_response, :threshold_for_debate, to: :parliament delegate :show_on_a_map?, to: :parliament with_options allow_nil: true, prefix: true do
  1. Identical code found in 2 nodes Locations: 0 1
delegate :name, :email, to: :creator delegate :code, :details, to: :rejection delegate :summary, :details, :created_at, :updated_at, to: :government_response delegate :date, :transcript_url, :video_url, :overview, to: :debate_outcome, prefix: :debate delegate :debate_pack_url, to: :debate_outcome, prefix: false end alias_attribute :open_at, :opened_at class << self def for_state(state) where(state: state) end def by_created_at reorder(created_at: :asc) end def by_most_recent_debate_outcome reorder(debate_outcome_at: :desc, created_at: :desc) end def by_waiting_for_debate_longest reorder(debate_threshold_reached_at: :asc, created_at: :desc) end def by_most_recent reorder(created_at: :desc) end def by_most_signatures reorder(signature_count: :desc) end def by_waiting_for_response_longest reorder(response_threshold_reached_at: :asc, created_at: :desc) end def awaiting_debate_date debate_threshold_reached.not_scheduled end def awaiting_response response_threshold_reached.not_responded end def not_responded where(government_response_at: nil) end def with_response where.not(government_response_at: nil).preload(:government_response) end def response_threshold_reached where.not(response_threshold_reached_at: nil) end def published where(state: PUBLISHED_STATES) end def moderated where(state: MODERATED_STATES) end def stopped where(state: STOPPED_STATE) end def closed where(state: CLOSED_STATE) end def rejected where(state: REJECTED_STATE) end def hidden where(state: HIDDEN_STATE) end def debateable where(state: DEBATABLE_STATES) end def debated where(debate_state: 'debated').preload(:debate_outcome) end def not_debated where(debate_state: 'not_debated') end def debate_threshold_reached where.not(debate_threshold_reached_at: nil) end def debate_scheduled where.not(scheduled_debate_date: nil) end def not_scheduled where(scheduled_debate_date: nil) end def with_debate_outcome where.not(debate_outcome_at: nil) end def with_debated_outcome debated.where.not(debate_outcome_at: nil) end def visible where(state: VISIBLE_STATES) end def in_need_of_marking_as_debated(date = Date.current) where(scheduled_debate_state.and(debate_date_in_the_past(date))) end def mark_petitions_as_debated!(date = Date.current)
  1. Archived::Petition has missing safe method 'mark_petitions_as_debated!'
in_need_of_marking_as_debated(date).update_all(debate_state: 'debated') end def in_debate_queue where(threshold_for_debate_reached.or(scheduled_for_debate)) end private def debate_date_in_the_past(date) arel_table[:scheduled_debate_date].lt(date) end def scheduled_debate_state arel_table[:debate_state].eq('scheduled') end def threshold_for_debate_reached arel_table[:debate_threshold_reached_at].not_eq(nil) end def scheduled_for_debate arel_table[:scheduled_debate_date].not_eq(nil) end end def moderated? state.in?(MODERATED_STATES) end def can_have_debate_added? state.in?(DEBATABLE_STATES) end def stopped? state == STOPPED_STATE end def closed? state == CLOSED_STATE end def rejected? state == REJECTED_STATE end def hidden? state == HIDDEN_STATE end def published? state.in?(PUBLISHED_STATES) end def duration if parliament.petition_duration? parliament.petition_duration elsif opened_at? calculate_petition_duration else 0 end end def closed_early_due_to_election? closed_at == parliament.dissolution_at end def government_response? government_response_at && government_response end def threshold_for_debate_reached? signature_count >= parliament.threshold_for_debate end def threshold_for_response_reached? signature_count >= parliament.threshold_for_response end def signatures_by_constituency if defined?(@_signatures_by_constituency) @_signatures_by_constituency else if signatures_by_constituency? @_signatures_by_constituency = calculate_signatures_by_constituency(super) else [] end end end def signatures_by_country if defined?(@_signatures_by_country) @_signatures_by_country else if signatures_by_country? @_signatures_by_country = calculate_signatures_by_country(super) else [] end end end def get_email_requested_at_for(name) self["email_requested_for_#{name}_at"] end def set_email_requested_at_for(name, to: Time.current) update_column("email_requested_for_#{name}_at", to) end def signatures_to_email_for(name) if timestamp = get_email_requested_at_for(name) signatures.need_emailing_for(name, since: timestamp) else raise ArgumentError, "The #{name} email has not been requested for petition #{id}" end end def update_debate_state self.debate_state = evaluate_debate_state end def update_lock!(user, now = Time.current)
  1. Archived::Petition takes parameters ['now', 'user'] to 3 methods Locations: 0 1 2
  2. Archived::Petition has missing safe method 'update_lock!'
if locked_by == user
  1. Archived::Petition#update_lock! is controlled by argument 'user'
update!(locked_at: now) end end def checkout!(user, now = Time.current)
  1. Identical code found in 2 nodes Locations: 0 1
  2. Archived::Petition takes parameters ['now', 'user'] to 3 methods Locations: 0 1 2
  3. Archived::Petition has missing safe method 'checkout!'
with_lock do if locked_by.present? && locked_by != user false else update!(locked_by: user, locked_at: now) end end end def force_checkout!(user, now = Time.current)
  1. Archived::Petition takes parameters ['now', 'user'] to 3 methods Locations: 0 1 2
  2. Archived::Petition has missing safe method 'force_checkout!'
update!(locked_by: user, locked_at: now) end def release!(user)
  1. Identical code found in 2 nodes Locations: 0 1
  2. Archived::Petition has missing safe method 'release!'
with_lock do if locked_by.present? && locked_by == user
  1. Archived::Petition#release! is controlled by argument 'user'
update!(locked_by: nil, locked_at: nil) end end end private def evaluate_debate_state if scheduled_debate_date? scheduled_debate_date > Date.current ? 'scheduled' : 'debated' else 'awaiting' end end def calculate_petition_duration
  1. Archived::Petition#calculate_petition_duration has a flog score of 46
if opened_at + 3.months == closed_at 3 elsif opened_at + 6.months == closed_at 6 elsif opened_at + 9.months == closed_at 9 elsif opened_at + 12.months == closed_at 12 else Rational(closed_at - opened_at, 86400 * 30).to_f end end def constituencies(external_ids)
  1. Archived::Petition#constituencies doesn't depend on instance state (maybe move it to another class?)
Constituency.where(external_id: external_ids).order(:name) end def calculate_signatures_by_constituency(hash) constituencies(hash.keys).map do |constituency| { name: constituency.name,
  1. Archived::Petition#calculate_signatures_by_constituency refers to 'constituency' more than self (maybe move it to another class?) Locations: 0 1 2 3
ons_code: constituency.ons_code,
  1. Archived::Petition#calculate_signatures_by_constituency refers to 'constituency' more than self (maybe move it to another class?) Locations: 0 1 2 3
mp: constituency.mp_name,
  1. Archived::Petition#calculate_signatures_by_constituency refers to 'constituency' more than self (maybe move it to another class?) Locations: 0 1 2 3
signature_count: hash[constituency.external_id]
  1. Archived::Petition#calculate_signatures_by_constituency refers to 'constituency' more than self (maybe move it to another class?) Locations: 0 1 2 3
} end end def locations(codes)
  1. Archived::Petition#locations doesn't depend on instance state (maybe move it to another class?)
Location.where(code: codes).order(:name) end def calculate_signatures_by_country(hash) locations(hash.keys).map do |location| { name: location.name,
  1. Archived::Petition#calculate_signatures_by_country refers to 'location' more than self (maybe move it to another class?) Locations: 0 1 2
code: location.code,
  1. Archived::Petition#calculate_signatures_by_country calls 'location.code' 2 times Locations: 0 1
  2. Archived::Petition#calculate_signatures_by_country refers to 'location' more than self (maybe move it to another class?) Locations: 0 1 2
signature_count: hash[location.code]
  1. Archived::Petition#calculate_signatures_by_country calls 'location.code' 2 times Locations: 0 1
  2. Archived::Petition#calculate_signatures_by_country refers to 'location' more than self (maybe move it to another class?) Locations: 0 1 2
} end end end end