forked from tip4commit/tip4commit
/
project.rb
247 lines (203 loc) · 6.37 KB
/
project.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
class Project < ActiveRecord::Base
has_many :deposits # todo: only confirmed deposits that have amount > paid_out
has_many :tips, inverse_of: :project
accepts_nested_attributes_for :tips
has_many :collaborators
has_many :sendmanies, inverse_of: :project
has_many :cold_storage_transfers
has_one :tipping_policies_text, inverse_of: :project
accepts_nested_attributes_for :tipping_policies_text
validates :name, presence: true
before_validation :strip_full_name
scope :enabled, -> { where(disabled: false) }
scope :disabled, -> { where(disabled: true) }
def update_github_info repo
self.github_id = repo.id
self.name = repo.name
self.full_name = repo.full_name
self.source_full_name = repo.source.full_name rescue ''
self.description = repo.description
self.watchers_count = repo.watchers_count
self.language = repo.language
self.save!
end
def update_github_collaborators(github_collaborators)
github_logins = github_collaborators.map(&:login)
existing_logins = collaborators.map(&:login)
collaborators.each do |collaborator|
unless github_logins.include?(collaborator.login)
collaborator.mark_for_destruction
end
end
github_collaborators.each do |github_collaborator|
unless existing_logins.include?(github_collaborator.login)
collaborators.build(login: github_collaborator.login)
end
end
save!
end
def github_url
"https://github.com/#{full_name}" if full_name.present?
end
def source_github_url
"https://github.com/#{source_full_name}"
end
def get_commits
begin
commits = Timeout::timeout(90) do
client = Octokit::Client.new \
:client_id => CONFIG['github']['key'],
:client_secret => CONFIG['github']['secret'],
:per_page => 100
client.commits(full_name)
end
rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError,
Errno::ETIMEDOUT, Faraday::Error::ConnectionFailed => e
Rails.logger.info "Project ##{id}: #{e.class} happened"
rescue StandardError => e
Airbrake.notify(e)
end
sleep(1)
commits || []
end
def tip_commits
return unless self.deposits.any?
get_commits.each do |commit|
# Filter merge request
next if commit.commit.message =~ /^(Merge\s|auto\smerge)/
# Filter fake emails
next unless commit.commit.author.email =~ Devise::email_regexp
# Filter commited after t4c project creation
next unless commit.commit.committer.date > self.deposits.first.created_at
Project.transaction do
tip_for commit
update_attribute :last_commit, commit.sha
end
end
end
def tip_for commit
email = commit.commit.author.email
if nickname = commit.author.try(:login)
user = User.find_by(nickname: nickname)
end
user ||= User.find_by(email: email)
if (next_tip_amount > 0) &&
Tip.find_by(commit: commit.sha).nil?
# create user
unless user
generated_password = Devise.friendly_token.first(8)
user = User.create(
email: email,
password: generated_password,
name: commit.commit.author.name,
nickname: nickname,
)
end
if nickname
user.update nickname: nickname
end
if hold_tips
amount = nil
else
amount = next_tip_amount
end
# create tip
tip = tips.create!({
user: user,
amount: amount,
commit: commit.sha,
commit_message: ActionController::Base.helpers.truncate(commit.commit.message, length: 100),
})
tip.notify_user
Rails.logger.info " Tip created #{tip.inspect}"
end
end
def available_amount
self.deposits.where("confirmations > 0").map(&:available_amount).sum - tips_paid_amount
end
def unconfirmed_amount
self.deposits.where(:confirmations => 0).map(&:available_amount).sum
end
def tips_paid_amount
self.tips.select(&:decided?).reject(&:refunded?).sum(&:amount)
end
def tips_paid_unclaimed_amount
self.tips.non_refunded.unclaimed.sum(:amount)
end
def next_tip_amount
(CONFIG["tip"]*available_amount).ceil
end
def self.update_cache
find_each do |project|
project.update available_amount_cache: project.available_amount
end
end
def github_info
client = Octokit::Client.new \
:client_id => CONFIG['github']['key'],
:client_secret => CONFIG['github']['secret']
if github_id.present?
client.get("/repositories/#{github_id}")
else
client.repo(full_name)
end
end
def github_collaborators
client = Octokit::Client.new \
:client_id => CONFIG['github']['key'],
:client_secret => CONFIG['github']['secret']
client.get("/repos/#{full_name}/collaborators") +
(client.get("/orgs/#{full_name.split('/').first}/members") rescue [])
end
def update_info
begin
update_github_info(github_info)
update_github_collaborators(github_collaborators)
rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError,
Errno::ETIMEDOUT, Faraday::Error::ConnectionFailed => e
Rails.logger.info "Project ##{id}: #{e.class} happened"
rescue StandardError => e
Airbrake.notify(e)
end
end
def tips_to_pay
tips.select(&:to_pay?)
end
def amount_to_pay
tips_to_pay.sum(&:amount)
end
def has_undecided_tips?
tips.undecided.any?
end
def commit_url(commit)
"https://github.com/#{full_name}/commit/#{commit}"
end
def cold_storage_amount
cold_storage_transfers.to_a.select(&:confirmed?).sum(&:amount)
end
def send_to_cold_storage!(amount, address_index = 0)
address = CONFIG["cold_storage"].try(:[], "addresses").try(:[], address_index)
raise "No cold storage address" if address.blank?
BitcoinDaemon.instance.send_many(address_label, {address => amount.to_f})
end
def paid_fee
[
sendmanies.map(&:fee),
cold_storage_transfers.map(&:fee),
].flatten.compact.sum
end
def strip_full_name
if full_name_changed? and full_name.present?
self.full_name = full_name.gsub(/https?\:\/\/github.com\//, '')
end
end
def auto_tip_commits
!hold_tips
end
def auto_tip_commits=(value)
self.hold_tips = case value
when false, nil, "0" then true
else false
end
end
end