-
Notifications
You must be signed in to change notification settings - Fork 1
/
bill.rb
189 lines (156 loc) · 4.66 KB
/
bill.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# frozen_string_literal: true
# typed: true
# == Schema Information
#
# Table name: bills
#
# id :integer not null, primary key
# external_id :string not null
# external_version :string
# title :string not null
# link :string
# chamber :string not null
# introduced_date_time_utc :datetime not null
# house_vote_date_time_utc :datetime
# senate_vote_date_time_utc :datetime
# level :string not null
# category :string not null
# summary :text
# legislator_id :integer not null
# sway_locale_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# status :string
# active :boolean
# audio_bucket_path :string
# audio_by_line :string
#
class Bill < ApplicationRecord
extend T::Sig
belongs_to :legislator
belongs_to :sway_locale
has_one :bill_score, dependent: :destroy
has_many :bill_cosponsors, dependent: :destroy
has_many :votes, inverse_of: :bill, dependent: :destroy
has_many :legislator_votes, inverse_of: :bill, dependent: :destroy
has_many :organization_bill_positions, inverse_of: :bill, dependent: :destroy
before_save :downcase_status, :determine_level, :determine_chamber
after_create :send_notifications
validates :external_id, uniqueness: {scope: :sway_locale_id, allow_nil: true}
scope :of_the_week, -> { last }
class Status
PASSED = "passed"
FAILED = "failed"
COMMITTEE = "committee"
VETOED = "vetoed"
end.freeze
STATUSES = [Status::PASSED.freeze, Status::FAILED.freeze, Status::COMMITTEE.freeze, Status::VETOED.freeze].freeze
sig { returns(SwayLocale) }
def sway_locale
T.cast(super, SwayLocale)
end
sig { returns(Legislator) }
def legislator
T.cast(super, Legislator)
end
def active
if introduced_date_time_utc.before?(sway_locale.current_session_start_date)
false
else
super.nil? ? true : super
end
end
sig { returns(T.nilable(Vote)) }
def vote
votes.last
end
# Render a single bill from a controller
def render(current_user)
{
bill: to_builder.attributes!,
positions: organization_bill_positions.map { |obp| obp.to_builder.attributes! },
legislatorVotes: legislator_votes.map { |lv| lv.to_builder.attributes! },
sponsor: legislator.to_builder.attributes!,
userVote: UserVote.find_by(
user: current_user,
bill_id: id
)&.attributes
}
end
sig { returns(Jbuilder) }
def to_builder
Jbuilder.new do |b|
b.id id
b.external_id external_id
b.external_version external_version
b.title title
b.summary summary
b.link link
b.chamber chamber
b.level level
b.category category
b.status status
b.active active
b.audio_bucket_path audio_bucket_path
b.audio_by_line audio_by_line
b.vote_date_time_utc vote_date_time_utc
b.introduced_date_time_utc introduced_date_time_utc
b.house_vote_date_time_utc house_vote_date_time_utc
b.senate_vote_date_time_utc senate_vote_date_time_utc
b.vote vote&.to_builder&.attributes!
b.legislator_id legislator_id
b.sway_locale_id sway_locale_id
b.created_at created_at
end
end
private
def vote_date_time_utc
h = house_vote_date_time_utc
s = senate_vote_date_time_utc
return nil unless h || s
if h && s
h.before?(s) ? h : s
else
h || s
end
end
# after initialize
def determine_level
return if level.present? || sway_locale.nil?
self.level = if sway_locale.congress?
"National"
elsif sway_locale.region?
"Regional"
else
"Local"
end
end
def determine_chamber
return if chamber.present? || sway_locale.nil?
if sway_locale.congress? || sway_locale.region?
# noop
else
self.chamber = "council"
end
end
# before save
sig { void }
def downcase_status
s = status
return unless s
if STATUSES.include?(s.downcase)
self.status = s.downcase
else
Rails.logger.warn("Bill.downcase_status - received status of #{s} is NOT valid. Should be one of #{STATUSES.join(", ")}")
self.status = nil
end
end
# after create
sig { void }
def send_notifications
SwayPushNotificationService.new(
title: "New Bill of the Week",
body: "#{title} in #{sway_locale.human_name}"
).send_push_notification
end
end