-
Notifications
You must be signed in to change notification settings - Fork 0
/
patron_functions.rb
263 lines (229 loc) · 9.61 KB
/
patron_functions.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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# authenticates to the API using the user-specific access token.
# that access token should have been previously generated using the client
# token and secret for the application- see
# https://www.patreon.com/portal/start/quick-start
def connect_to_patreon
if !File.exist?("#{File.dirname(__FILE__)}/credentials.rb")
puts "You need to populate the credentials.rb file."
puts "See credentials.rb.example for more details."
exit 1
end
require "#{File.dirname(__FILE__)}/credentials.rb"
if PATREON_ACCESS_TOKEN.empty?
puts "PATREON_ACCESS_TOKEN not set in credentials.rb."
exit 1
end
require 'patreon'
Patreon::API.new(PATREON_ACCESS_TOKEN)
end
def connect_to_vanilla
if !File.exist?("#{File.dirname(__FILE__)}/credentials.rb")
puts "You need to populate the credentials.rb file."
puts "See credentials.rb.example for more details."
exit 1
end
require "#{File.dirname(__FILE__)}/credentials.rb"
if DB_HOST.empty? || DB_USER.empty? || DB_PASS.empty? || DB_DB.empty?
puts "Database credentials not provided in credentials.rb."
exit 1
end
require 'mysql2'
Mysql2::Client.new(host: DB_HOST, username: DB_USER, password: DB_PASS, database: DB_DB)
end
# get ALL the data the API will give us. it's a mess and repetitive, so
# basically unusable in this state.
def fetch_patron_data(api_client)
api_client.fetch_campaign_and_patrons.data.first
end
# look in the previously fetched API data to get all reward levels
# returns an array containing a hash of details for each reward level
def reward_levels(patron_data)
patron_data.rewards.collect{|r|
{
id: r.id,
type: r.type,
amount: r.amount_cents,
title: r.title,
description: r.description
}
}.sort_by{|r| r[:amount]}
end
# look in the previously fetched API data to get all patrons
# returns an array containing a hash of details for each patron and their
# rewards, if applicable
def all_patrons(patron_data)
patron_data.pledges.collect{|p|
{
full_name: p.patron.full_name,
email: p.patron.email,
amount: p.amount_cents,
reward_id: (p.reward.respond_to?(:id) ? p.reward.id : nil),
reward_title: (p.reward.respond_to?(:id) ? p.reward.title : nil)
}
}
end
# for the below functions, every pledge above a specific level will get a
# reward. to avoid hard coding too much (just minimum reward titles),
# programmatically get all reward levels that qualify
def all_award_levels_above(reward_title, rewards)
relevant_levels = []
target_found = false
rewards.each do |reward|
if target_found
relevant_levels << reward[:id]
elsif reward[:title] == reward_title
target_found = true
relevant_levels << reward[:id]
end
end
return relevant_levels
end
# look in the vanilla database to find the earliest discussion with the given
# title (in case some joker created a duplicate discussion)
# return false if no matching discussion was found
def get_vanilla_discussion(post_title, db_conn)
query = db_conn.prepare("select * from GDN_Discussion where Name = ? order by DateInserted ASC limit 1")
results = query.execute(post_title)
results.size == 1 or return false
return results.first
end
# look in the vanilla database to find the YAGA badge with the given name
# return false if no matching badge was found
def get_badge(badge_name, db_conn)
query = db_conn.prepare("select * from GDN_Badge where Name = ?")
results = query.execute(badge_name)
results.size == 1 or return false
return results.first
end
# try to connect patrons to forum user accounts using full_name/handle or
# email/email. returns an array of selected data from the vanilla DB
def patron_forum_users(patrons, db_conn)
users = []
patrons.each do |p|
query = db_conn.prepare("select UserID, Name, Email, Points, CountBadges from GDN_User where Name = ? or Email = ? order by UserID DESC")
results = query.execute(p[:full_name], p[:email])
(results.size == 0) and next
users << results.first
end
return users
end
# create a new post on the virtual wall discussion with all qualifying patron
# names
def create_virtual_wall_post(reward_levels, patrons, db_conn)
puts "Creating virtual wall post..."
award_patrons = patrons.select{|p| reward_levels.include?(p[:reward_id])}.sort_by{|p| p[:amount]}.reverse
users = patron_forum_users(award_patrons, db_conn)
unless users.size > 0
puts "\tNo eligible user forum accounts found!"
return false
end
no_account_users = []
if users.size < award_patrons.size
found_user_names = users.collect{|u| u['Name']}
found_user_emails = users.collect{|u| u['Email']}
no_account_users = award_patrons.reject{|p| found_user_names.include?(p[:full_name]) || found_user_emails.include?(p[:email])}
end
virtual_wall_post = get_vanilla_discussion('Patreon Virtual Wall', db_conn)
unless virtual_wall_post
puts "\tVirtual wall discussion not found!"
return false
end
# build comment content
post_content = "Thank you to this month's <a href='https://www.patreon.com/biohack/posts'>Patreon</a> supporters!<br /><br /><ul>"
users.each do |u|
post_content << "<li>@#{u['Name']}</li>"
end
no_account_users.each do |na|
post_content << "<li>#{na[:full_name]}</li>"
end
post_content << "</ul>"
if no_account_users.size > 0
post_content << "<br />Forum accounts for patrons were linked where a matching username or email address was found."
end
# create comment
query = db_conn.prepare("insert into GDN_Comment (DiscussionID, InsertUserID, Body, Format, DateInserted) values (?, ?, ?, ?, ?)")
results = query.execute(virtual_wall_post['DiscussionID'], virtual_wall_post['InsertUserID'], post_content, 'Html', Time.now.getutc)
comment_id = db_conn.last_id
# update discussion metadata
if virtual_wall_post['FirstCommentID'].nil?
# this is the first post!
query = db_conn.prepare("update GDN_Discussion set FirstCommentID = ?, LastCommentID = ?, CountComments = ?, DateLastComment = ? where DiscussionID = ?")
results = query.execute(comment_id, comment_id, virtual_wall_post['CountComments']+1, Time.now.getutc, virtual_wall_post['DiscussionID'])
else
query = db_conn.prepare("update GDN_Discussion set LastCommentID = ?, CountComments = ?, DateLastComment = ?, LastCommentUserID = ? where DiscussionID = ?")
results = query.execute(comment_id, virtual_wall_post['CountComments']+1, Time.now.getutc, virtual_wall_post['InsertUserID'], virtual_wall_post['DiscussionID'])
end
# update user metadata
query = db_conn.prepare("update GDN_User set CountComments = CountComments + 1 where UserID = ?")
results = query.execute(virtual_wall_post['InsertUserID'])
puts "\tPost (thanking #{users.size} found users) created!"
end
# remove a badge from all users, updating metadata
def remove_badge(badge, db_conn)
query = db_conn.prepare("select * from GDN_BadgeAward where BadgeID = ?")
results = query.execute(badge['BadgeID'])
results.size > 0 or return true
results.each do |award|
remove_badge_award = db_conn.prepare("delete from GDN_BadgeAward where BadgeID = ? and UserID = ?")
remove_badge_award.execute(award['BadgeID'], award['UserID'])
update_user = db_conn.prepare("update GDN_User set CountBadges = CountBadges-1, Points = Points-? where UserID = ?")
update_user.execute(badge['AwardValue'], award['UserID'])
update_points = db_conn.prepare("update GDN_UserPoints set Points = Points-? where UserID = ?")
update_points.execute(badge['AwardValue'], award['UserID'])
end
end
# award a badge to a user, updating metadata
def award_badge(user, badge, db_conn)
add_badge_award = db_conn.prepare("insert into GDN_BadgeAward (BadgeID, UserID, InsertUserID, DateInserted) values (?, ?, ?, ?)")
add_badge_award.execute(badge['BadgeID'], user['UserID'], user['UserID'], Time.now.getutc)
update_user = db_conn.prepare("update GDN_User set CountBadges = CountBadges+1, Points = Points+? where UserID = ?")
update_user.execute(badge['AwardValue'], user['UserID'])
update_points = db_conn.prepare("update GDN_UserPoints set Points = Points+? where UserID = ?" )
update_points.execute(badge['AwardValue'], user['UserID'])
end
# remove all old patron badges
# award new ones to qualifying accounts
def award_patreon_badges(reward_levels, patrons, db_conn)
puts "Awarding patreon badges..."
badge_patreon = get_badge('Patreon Badge', db_conn)
unless badge_patreon
puts "\tBadge not found"
return false
end
# remove all old badges
remove_badge(badge_patreon, db_conn)
# award new badges
award_patrons = patrons.select{|p| reward_levels.include?(p[:reward_id])}
users = patron_forum_users(award_patrons, db_conn)
unless users.size > 0
puts "\tNo eligible user forum accounts found!"
return false
end
users.each do |user|
award_badge(user, badge_patreon, db_conn)
end
puts "\tBadge awarded to #{users.size} found users!"
end
# remove all old gold patron badges
# award new ones to qualifying accounts
def award_gold_patreon_badges(reward_levels, patrons, db_conn)
puts "Awarding gold patreon badges..."
badge_gold_patreon = get_badge('Patreon Gold Badge', db_conn)
unless badge_gold_patreon
puts "\tGold badge not found!"
return false
end
# remove all old badges
remove_badge(badge_gold_patreon, db_conn)
# award new badges
award_patrons = patrons.select{|p| reward_levels.include?(p[:reward_id])}
users = patron_forum_users(award_patrons, db_conn)
unless users.size > 0
puts "\tNo eligible user forum accounts found!"
return false
end
users.each do |user|
award_badge(user, badge_gold_patreon, db_conn)
end
puts "\tBadge awarded to #{users.size} found users!"
end