1require 'textacular/searchable'
 
2require_dependency 'archived'
 
3
 
4module Archived
  • Class "Petition" has 378 lines. It should have 300 or less. » roodi
5  class Petition < ActiveRecord::Base
 
6    STOPPED_STATE = 'stopped'
 
7    CLOSED_STATE = 'closed'
 
8    HIDDEN_STATE = 'hidden'
 
 9    REJECTED_STATE = 'rejected'
 
10    STATES = [STOPPED_STATE, CLOSED_STATE, HIDDEN_STATE, REJECTED_STATE]
 
11    PUBLISHED_STATES = [CLOSED_STATE]
 
12    VISIBLE_STATES = [CLOSED_STATE, REJECTED_STATE]
 
13    MODERATED_STATES = [CLOSED_STATE, HIDDEN_STATE, REJECTED_STATE]
 
14    DEBATABLE_STATES = [CLOSED_STATE]
 
 
16    belongs_to :parliament, inverse_of: :petitions, required: true
 
17    belongs_to :locked_by, class_name: 'AdminUser'
 
 
19    has_one :creator, -> { creator }, class_name: "Signature"
 
20    has_one :debate_outcome, dependent: :destroy
 
21    has_one :government_response, dependent: :destroy
 
22    has_one :note, dependent: :destroy
 
23    has_one :rejection, dependent: :destroy
 
 
25    has_many :emails, :dependent => :destroy
 
26    has_many :signatures
 
27    has_many :sponsors, -> { sponsors }, class_name: "Signature"
 
 
29    validates :action, presence: true, length: { maximum: 150 }
 
30    validates :background, length: { maximum: 300 }, allow_blank: true
 
31    validates :additional_details, length: { maximum: 1000 }, allow_blank: true
 
32    validates :state, presence: true, inclusion: STATES
 
33    validates :closed_at, presence: true, if: :closed?
 
 
35    before_save :update_debate_state, if: :scheduled_debate_date_changed?
 
 
37    extend Searchable(:action, :background, :additional_details)
 
38    include Browseable, Taggable
 
 
40    filter :parliament
 
 
42    facet :all, -> { visible.by_most_signatures }
 
43    facet :awaiting_response, -> { awaiting_response.by_waiting_for_response_longest }
 
44    facet :awaiting_debate_date, -> { awaiting_debate_date.by_waiting_for_debate_longest }
 
45    facet :with_debate_outcome, -> { with_debate_outcome.by_most_recent_debate_outcome }
 
46    facet :with_debated_outcome, -> { with_debated_outcome.by_most_recent_debate_outcome }
 
47    facet :published, -> { published.by_most_signatures }
 
48    facet :stopped, -> { stopped.by_most_signatures }
 
49    facet :closed, -> { closed.by_most_signatures }
 
50    facet :rejected, -> { rejected.by_most_signatures }
 
51    facet :hidden, -> { hidden.by_most_recent }
 
52    facet :with_response, -> { with_response.by_most_signatures }
 
53    facet :debated, -> { debated.by_most_recent_debate_outcome }
 
54    facet :not_debated, -> { not_debated.by_most_recent_debate_outcome }
 
55    facet :by_most_signatures, -> { by_most_signatures }
 
56    facet :by_created_at, -> { by_created_at }
 
57    facet :in_debate_queue, -> { in_debate_queue.by_waiting_for_debate_longest }
 
 
59    default_scope { preload(:parliament) }
 
 
61    delegate :threshold_for_response, :threshold_for_debate, to: :parliament
 
62    delegate :show_on_a_map?, to: :parliament
 
 
64    with_options allow_nil: true, prefix: true do
 
65      delegate :name, :email, to: :creator
 
66      delegate :code, :details, to: :rejection
 
67      delegate :summary, :details, :created_at, :updated_at, to: :government_response
 
68      delegate :date, :transcript_url, :video_url, :overview, to: :debate_outcome, prefix: :debate
 
69      delegate :debate_pack_url, to: :debate_outcome, prefix: false
 
70    end
 
 
72    alias_attribute :open_at, :opened_at
 
 
74    class << self
 
75      def for_state(state)
 
76        where(state: state)
 
77      end
 
 
79      def by_created_at
 
80        reorder(created_at: :asc)
 
81      end
 
 
83      def by_most_recent_debate_outcome
 
84        reorder(debate_outcome_at: :desc, created_at: :desc)
 
85      end
 
 
87      def by_waiting_for_debate_longest
 
88        reorder(debate_threshold_reached_at: :asc, created_at: :desc)
 
89      end
 
 
91      def by_most_recent
 
92        reorder(created_at: :desc)
 
93      end
 
 
95      def by_most_signatures
 
96        reorder(signature_count: :desc)
 
97      end
 
 
 99      def by_waiting_for_response_longest
 
100        reorder(response_threshold_reached_at: :asc, created_at: :desc)
 
101      end
 
 
103      def awaiting_debate_date
 
104        debate_threshold_reached.not_scheduled
 
105      end
 
 
107      def awaiting_response
 
108        response_threshold_reached.not_responded
 
109      end
 
 
111      def not_responded
 
112        where(government_response_at: nil)
 
113      end
 
 
115      def with_response
 
116        where.not(government_response_at: nil).preload(:government_response)
 
117      end
 
 
119      def response_threshold_reached
 
120        where.not(response_threshold_reached_at: nil)
 
121      end
 
 
123      def published
 
124        where(state: PUBLISHED_STATES)
 
125      end
 
 
127      def moderated
 
128        where(state: MODERATED_STATES)
 
129      end
 
 
131      def stopped
 
132        where(state: STOPPED_STATE)
 
133      end
 
 
135      def closed
 
136        where(state: CLOSED_STATE)
 
137      end
 
 
139      def rejected
 
140        where(state: REJECTED_STATE)
 
141      end
 
 
143      def hidden
 
144        where(state: HIDDEN_STATE)
 
145      end
 
 
147      def debateable
 
148        where(state: DEBATABLE_STATES)
 
149      end
 
 
151      def debated
 
152        where(debate_state: 'debated').preload(:debate_outcome)
 
153      end
 
 
155      def not_debated
 
156        where(debate_state: 'not_debated')
 
157      end
 
 
159      def debate_threshold_reached
 
160        where.not(debate_threshold_reached_at: nil)
 
161      end
 
 
163      def debate_scheduled
 
164        where.not(scheduled_debate_date: nil)
 
165      end
 
 
167      def not_scheduled
 
168        where(scheduled_debate_date: nil)
 
169      end
 
 
171      def with_debate_outcome
 
172        where.not(debate_outcome_at: nil)
 
173      end
 
 
175      def with_debated_outcome
 
176        debated.where.not(debate_outcome_at: nil)
 
177      end
 
 
179      def visible
 
180        where(state: VISIBLE_STATES)
 
181      end
 
 
183      def in_need_of_marking_as_debated(date = Date.current)
 
184        where(scheduled_debate_state.and(debate_date_in_the_past(date)))
 
185      end
 
 
187      def mark_petitions_as_debated!(date = Date.current)
 
188        in_need_of_marking_as_debated(date).update_all(debate_state: 'debated')
 
189      end
 
 
191      def in_debate_queue
 
192        where(threshold_for_debate_reached.or(scheduled_for_debate))
 
193      end
 
 
195      private
 
 
197      def debate_date_in_the_past(date)
 
198        arel_table[:scheduled_debate_date].lt(date)
 
199      end
 
 
201      def scheduled_debate_state
 
202        arel_table[:debate_state].eq('scheduled')
 
203      end
 
 
205      def threshold_for_debate_reached
 
206        arel_table[:debate_threshold_reached_at].not_eq(nil)
 
207      end
 
 
209      def scheduled_for_debate
 
210        arel_table[:scheduled_debate_date].not_eq(nil)
 
211      end
 
212    end
 
 
214    def moderated?
 
215      state.in?(MODERATED_STATES)
 
216    end
 
 
218    def can_have_debate_added?
 
219      state.in?(DEBATABLE_STATES)
 
220    end
 
 
222    def stopped?
 
223      state == STOPPED_STATE
 
224    end
 
 
226    def closed?
 
227      state == CLOSED_STATE
 
228    end
 
 
230    def rejected?
 
231      state == REJECTED_STATE
 
232    end
 
 
234    def hidden?
 
235      state == HIDDEN_STATE
 
236    end
 
 
238    def published?
 
239      state.in?(PUBLISHED_STATES)
 
240    end
 
 
242    def duration
 
243      if parliament.petition_duration?
 
244        parliament.petition_duration
 
245      elsif opened_at?
 
246        calculate_petition_duration
 
247      else
 
248        0
 
249      end
 
250    end
 
 
252    def closed_early_due_to_election?
 
253      closed_at == parliament.dissolution_at
 
254    end
 
 
256    def government_response?
 
257      government_response_at && government_response
 
258    end
 
 
260    def threshold_for_debate_reached?
 
261      signature_count >= parliament.threshold_for_debate
 
262    end
 
 
264    def threshold_for_response_reached?
 
265      signature_count >= parliament.threshold_for_response
 
266    end
 
 
268    def signatures_by_constituency
 
269      if defined?(@_signatures_by_constituency)
 
270        @_signatures_by_constituency
 
271      else
 
272        if signatures_by_constituency?
 
273          @_signatures_by_constituency = calculate_signatures_by_constituency(super)
 
274        else
 
275          []
 
276        end
 
277      end
 
278    end
 
 
280    def signatures_by_country
 
281      if defined?(@_signatures_by_country)
 
282        @_signatures_by_country
 
283      else
 
284        if signatures_by_country?
 
285          @_signatures_by_country = calculate_signatures_by_country(super)
 
286        else
 
287          []
 
288        end
 
289      end
 
290    end
 
 
292    def get_email_requested_at_for(name)
 
293      self["email_requested_for_#{name}_at"]
 
294    end
 
 
296    def set_email_requested_at_for(name, to: Time.current)
 
297      update_column("email_requested_for_#{name}_at", to)
 
298    end
 
 
300    def signatures_to_email_for(name)
  • Found = in conditional. It should probably be an == » roodi
301      if timestamp = get_email_requested_at_for(name)
 
302        signatures.need_emailing_for(name, since: timestamp)
 
303      else
 
304        raise ArgumentError, "The #{name} email has not been requested for petition #{id}"
 
305      end
 
306    end
 
 
308    def update_debate_state
 
309      self.debate_state = evaluate_debate_state
 
310    end
 
 
312    def update_lock!(user, now = Time.current)
 
313      if locked_by == user
 
314        update!(locked_at: now)
 
315      end
 
316    end
 
 
318    def checkout!(user, now = Time.current)
 
319      with_lock do
 
320        if locked_by.present? && locked_by != user
 
321          false
 
322        else
 
323          update!(locked_by: user, locked_at: now)
 
324        end
 
325      end
 
326    end
 
 
328    def force_checkout!(user, now = Time.current)
 
329      update!(locked_by: user, locked_at: now)
 
330    end
 
 
332    def release!(user)
 
333      with_lock do
 
334        if locked_by.present? && locked_by == user
 
335          update!(locked_by: nil, locked_at: nil)
 
336        end
 
337      end
 
338    end
 
 
340    private
 
 
342    def evaluate_debate_state
 
343      if scheduled_debate_date?
 
344        scheduled_debate_date > Date.current ? 'scheduled' : 'debated'
 
345      else
 
346        'awaiting'
 
347      end
 
348    end
 
 
350    def calculate_petition_duration
 
351      if opened_at + 3.months == closed_at
 
352        3
 
353      elsif opened_at + 6.months == closed_at
 
354        6
 
355      elsif opened_at + 9.months == closed_at
 
356        9
 
357      elsif opened_at + 12.months == closed_at
 
358        12
 
359      else
 
360        Rational(closed_at - opened_at, 86400 * 30).to_f
 
361      end
 
362    end
 
 
364    def constituencies(external_ids)
 
365      Constituency.where(external_id: external_ids).order(:name)
 
366    end
 
 
368    def calculate_signatures_by_constituency(hash)
 
369      constituencies(hash.keys).map do |constituency|
 
370        {
 
371          name: constituency.name,
 
372          ons_code: constituency.ons_code,
 
373          mp: constituency.mp_name,
 
374          signature_count: hash[constituency.external_id]
 
375        }
 
376      end
 
377    end
 
 
379    def locations(codes)
 
380      Location.where(code: codes).order(:name)
 
381    end
 
 
383    def calculate_signatures_by_country(hash)
 
384      locations(hash.keys).map do |location|
 
385        {
 
386          name: location.name,
 
387          code: location.code,
 
388          signature_count: hash[location.code]
 
389        }
 
390      end
 
391    end
 
392  end
 
393end