Updated

app/models/archived / signature.rb

F
318 lines of codes
46 methods
6.3 complexity/method
14 churn
290.66 complexity
184 duplications
require 'ipaddr' require_dependency 'archived' module Archived class Signature < ActiveRecord::Base
  1. Archived::Signature has no descriptive comment
  2. Archived::Signature has 7 constants
  3. Archived::Signature has at least 46 methods
include GeoipLookup ISO8601_TIMESTAMP = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\z/ PENDING_STATE = 'pending' FRAUDULENT_STATE = 'fraudulent' VALIDATED_STATE = 'validated' INVALIDATED_STATE = 'invalidated' STATES = [ PENDING_STATE, FRAUDULENT_STATE, VALIDATED_STATE, INVALIDATED_STATE ] TIMESTAMPS = { 'government_response' => :government_response_email_at, 'debate_scheduled' => :debate_scheduled_email_at, 'debate_outcome' => :debate_outcome_email_at, 'petition_email' => :petition_email_at } belongs_to :petition belongs_to :invalidation belongs_to :constituency, primary_key: :external_id validates :constituency_id, length: { maximum: 255 } validates :email, presence: true validates :location_code, presence: true validates :name, presence: true, length: { maximum: 255 } validates :state, presence: true, inclusion: { in: STATES } attr_readonly :sponsor, :creator before_destroy do !creator? end class << self def batch(id = 0, limit: 1000)
  1. Similar code found in 2 nodes Locations: 0 1
where(arel_table[:id].gteq(id)).order(id: :asc).limit(limit) end def by_most_recent order(created_at: :desc) end def column_name_for(timestamp) TIMESTAMPS.fetch(timestamp) rescue raise ArgumentError, "Unknown petition email timestamp: #{timestamp.inspect}" end def destroy!(signature_ids)
  1. Archived::Signature has missing safe method 'destroy!'
signatures = find(signature_ids) transaction do signatures.each do |signature| signature.destroy! end end end def for_domain(domain) where("SUBSTRING(email FROM POSITION('@' IN email) + 1) = ?", domain[1..-1]) end def for_email(email) where("(REGEXP_REPLACE(LEFT(email, POSITION('@' IN email) - 1), '\\.|\\+.+', '', 'g') || SUBSTRING(email FROM POSITION('@' IN email)) = ?)", normalize_email(email)) end def for_ip(ip) where("inet(ip_address) <<= inet(?)", ip) end def for_name(name) where(arel_table[:name].lower.eq(name.downcase)) end def for_petition(id) where(petition_id: id) end def for_postcode(postcode) where(postcode: PostcodeSanitizer.call(postcode)) end def for_sector(postcode) where("LEFT(postcode, -3) = ?", PostcodeSanitizer.call(postcode)[0..-4]) end def for_timestamp(timestamp, since:)
  1. Identical code found in 2 nodes Locations: 0 1
column = arel_table[column_name_for(timestamp)] where(column.eq(nil).or(column.lt(since))) end def need_emailing_for(timestamp, since:) validated.subscribed.for_timestamp(timestamp, since: since) end def subscribed where(notify_by_email: true) end def validated where(state: VALIDATED_STATE) end def creator where(arel_table[:creator].eq(true)) end def sponsors where(arel_table[:sponsor].eq(true)) end def search(query, options = {})
  1. Archived::Signature::search has a flog score of 76
  2. Archived::Signature#search has approx 20 statements
query = query.to_s state = options[:state] window = options[:window] page = [options[:page].to_i, 1].max scope = preload(:petition).by_most_recent if state.in?(STATES) scope = scope.where(state: state) end if window && window =~ ISO8601_TIMESTAMP starts_at = window.in_time_zone.at_beginning_of_hour
  1. Identical code found in 2 nodes Locations: 0 1
ends_at = starts_at.advance(hours: 1) scope = scope.where(created_at: starts_at..ends_at)
  1. Archived::Signature#search calls 'scope.where(created_at: starts_at..ends_at)' 2 times Locations: 0 1
elsif window =~ /\A\d+\z/ starts_at = window.to_i.seconds.ago ends_at = Time.current scope = scope.where(created_at: starts_at..ends_at)
  1. Archived::Signature#search calls 'scope.where(created_at: starts_at..ends_at)' 2 times Locations: 0 1
end
  1. Identical code found in 2 nodes Locations: 0 1
if ip_search?(query)
  1. Identical code found in 2 nodes Locations: 0 1
scope = scope.for_ip(query) elsif domain_search?(query) scope = scope.for_domain(query) elsif email_search?(query) scope = scope.for_email(query) elsif petition_search?(query) scope = scope.for_petition(query) elsif postcode_search?(query) scope = scope.for_postcode(query) elsif sector_search?(query) scope = scope.for_sector(query) else scope = scope.for_name(query) end scope.paginate(page: page, per_page: 50) end def subscribe!(signature_ids)
  1. Identical code found in 2 nodes Locations: 0 1
  2. Archived::Signature has missing safe method 'subscribe!'
signatures = find(signature_ids) transaction do signatures.each do |signature| signature.update!(notify_by_email: true) end end end def unsubscribe!(signature_ids)
  1. Identical code found in 2 nodes Locations: 0 1
  2. Archived::Signature has missing safe method 'unsubscribe!'
  3. Archived::Signature#unsubscribe! has approx 6 statements
signatures = find(signature_ids) transaction do signatures.each do |signature| if signature.creator? raise RuntimeError, "Can't unsubscribe the creator signature" elsif signature.pending? raise RuntimeError, "Can't unsubscribe a pending signature" else signature.update!(notify_by_email: false) end end end end private def ip_search?(query) IPAddr.new(query) rescue IPAddr::InvalidAddressError => e
  1. Archived::Signature#ip_search? has the variable name 'e'
false end def domain_search?(query) query.starts_with?('@') end def email_search?(query) query.include?('@') end def petition_search?(query) query =~ /\A\d+\z/ end def postcode_search?(query) PostcodeSanitizer.call(query) =~ PostcodeValidator::PATTERN end def sector_search?(query) PostcodeSanitizer.call(query) =~ /\A[A-Z]{1,2}[0-9][0-9A-Z]?XXX\z/ end def normalize_email(email) "#{normalize_user(email)}@#{normalize_domain(email)}" end def normalize_user(email) email.split("@").first.split("+").first.tr(".", "").downcase end def normalize_domain(email) email.split("@").last.downcase end end def get_email_sent_at_for(timestamp) self[column_name_for(timestamp)] end def set_email_sent_at_for(timestamp, to: Time.current) update_column(column_name_for(timestamp), to) end def pending? state == PENDING_STATE end def fraudulent? state == FRAUDULENT_STATE end def validated? state == VALIDATED_STATE end def invalidated? state == INVALIDATED_STATE end def subscribed? validated? && !unsubscribed? end def unsubscribed? notify_by_email == false end def unsubscribe!(token)
  1. Identical code found in 2 nodes Locations: 0 1
  2. Archived::Signature has missing safe method 'unsubscribe!'
if unsubscribed? errors.add(:base, "Already Unsubscribed") elsif unsubscribe_token != token
  1. Archived::Signature#unsubscribe! is controlled by argument 'token'
errors.add(:base, "Invalid Unsubscribe Token") else update(notify_by_email: false) end end def already_unsubscribed? errors[:base].include?("Already Unsubscribed") end def invalid_unsubscribe_token? errors[:base].include?("Invalid Unsubscribe Token") end def united_kingdom? location_code == 'GB' end alias_method :uk?, :united_kingdom? def location if postcode? "#{formatted_postcode}, #{location_code}" else location_code end end def account Mail::Address.new(email).local rescue Mail::Field::ParseError nil end def domain Mail::Address.new(email).domain rescue Mail::Field::ParseError nil end private def formatted_postcode if united_kingdom? postcode.gsub(/\A([A-Z0-9]+?)([A-Z0-9]{3})\z/, "\\1 \\2") else postcode end end def column_name_for(timestamp) self.class.column_name_for(timestamp) end end end