Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 258 lines (221 sloc) 12.835 kb
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
1 #!/usr/bin/python
2 #
3 # Copyright 2009 Jeff Verkoeyen.
4
5 import twitterbot
bde07cf Jeff Verkoeyen Add the ability to find people.
authored
6 import random
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
7
8 class Bot(twitterbot.StandardBot):
9 '''The findpassion twitter bot.
10 '''
11 def __init__(self):
12 twitterbot.StandardBot.__init__(self,
13 dbuser = "findpassion",
14 dbpass = "F1nd_P4sS10n456!",
15 dbdb = "findpassion",
16 twituser = 'findpassion',
17 twitpass = 'F1nd_P4sS10n123!')
18
19
20 ################################
21 # Cache some statistics
22
23 self.available_users = 0
24 for screen_name in self.existing_users:
25 self.available_users += self.existing_users[screen_name]['available_for_hire']
26
27
28 def execute(self):
29 tweets = self.getTweets()
58aa223 Jeff Verkoeyen Commit tweets immediately so that we don't run into an infinite loop.
authored
30 self.commitTweets()
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
31
be321d1 Jeff Verkoeyen Store updated users properly.
authored
32 self.updated_users = {}
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
33
34 if len(tweets) == 1:
35 print str(len(tweets)) + " new tweet"
36 elif len(tweets) > 1:
37 print str(len(tweets)) + " new tweets"
38 for tweet in tweets:
39 if tweet.user.screen_name in self.existing_users:
40 print tweet.user.screen_name+": " + tweet.text
41 self.parseCommands(tweet.user.screen_name, tweet.text)
42 else:
43 print "I don't know this person: " + tweet.user.screen_name
44
be321d1 Jeff Verkoeyen Store updated users properly.
authored
45 for screen_name in self.updated_users:
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
46 print "Firing off update to "+screen_name
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
47 self.notifyUser(screen_name, "Cheers! Your account's been updated")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
48
49
50 def parseCommands(self, screen_name, commands):
51 user = self.existing_users[screen_name]
52 updated_user = user.copy()
53 commands = commands.partition(' ')[2].strip().lower().split(' ')
54
55 init = commands[0]
56
57 if init == 'available':
58 updated_user['available_for_hire'] = True
59
60 elif init == 'unavailable':
61 updated_user['available_for_hire'] = False
62
63 elif init == 'how' and len(commands) > 1:
64 if commands[1].startswith('many'):
65 if self.available_users == 1:
66 people = 'person'
67 areis = 'is'
68 else:
69 people = 'people'
70 areis = 'are'
71 if self.available_users > 0:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
72 self.notifyUser(screen_name, "We currently know "+str(self.available_users)+" "+people+" who "+areis+" looking for work")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
73 else:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
74 self.notifyUser(screen_name, "We don't know anyone who's looking for work right now. Are you? Tweet \"@findpassion available\" to let us know")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
75
76 elif user['is_admin'] and init == 'accept' and len(commands) > 1:
77 if commands[1].startswith('class') and len(commands) > 2:
10f29f0 Jeff Verkoeyen Properly update the last tweet id and allow multiple class names.
authored
78 for class_name in ' '.join(commands[2:]).split(','):
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
79 print "Accepting class: "+class_name
4c12962 Jeff Verkoeyen Clean up text and trim names.
authored
80 class_name = class_name.strip()
10f29f0 Jeff Verkoeyen Properly update the last tweet id and allow multiple class names.
authored
81 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name))
82 class_data = self.cursor.fetchone()
83
84 if class_data == None:
85 self.cursor.execute("INSERT INTO classes(name, suggested_by, legit) VALUES(%s, %s, 1)", (class_name, user['id']))
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
86 self.notifyUser(screen_name, class_name+" doesn't exist, but it's now added")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
87 else:
10f29f0 Jeff Verkoeyen Properly update the last tweet id and allow multiple class names.
authored
88 if class_data[1]: # Legit?
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
89 self.notifyUser(screen_name, class_name+" is already legit")
10f29f0 Jeff Verkoeyen Properly update the last tweet id and allow multiple class names.
authored
90 else:
91 class_id = class_data[0]
92 self.cursor.execute("UPDATE classes SET legit=1 WHERE id=%s", (class_id))
93 self.cursor.execute("SELECT screen_name FROM votes LEFT JOIN followers on follower = id WHERE class = %s", (class_id))
94 rows = self.cursor.fetchall()
95 if len(rows) > 0:
96 for row in rows:
97 if not row[0] == screen_name:
98 self.notifyUser(row[0], "\""+class_name+"\" is now legit!")
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
99 self.notifyUser(screen_name, class_name+" is now legit")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
100
101 elif init == 'suggest' and len(commands) > 1:
102 if commands[1].startswith('class') and len(commands) > 2:
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
103 for class_name in ' '.join(commands[2:]).split(','):
104 class_name = class_name.strip()
105 print "Suggesting class: "+class_name
106 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name))
107 class_data = self.cursor.fetchone()
108 class_id = None
109 new_class = False
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
110
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
111 if class_data == None:
112 # This class doesn't exist; create it.
113 self.cursor.execute("INSERT INTO classes(name, suggested_by) VALUES(%s, %s)", (class_name, user['id']))
63a4845 Jeff Verkoeyen More minute text cleanup.
authored
114 class_id = self.conn.insert_id()
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
115 self.notifyUser(screen_name, "Thanks for suggesting a new class! If it's accepted into the list we'll tweet you back")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
116 new_class = True
117 else:
118 class_id = class_data[0]
119 if class_data[1]: # Legit?
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
120 self.notifyUser(screen_name, class_name+" is already legit")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
121 return
122
123 # At this point we know the class's either new or not legit
124 # Check if they've already voted.
125 self.cursor.execute("SELECT follower FROM votes WHERE follower=%s AND class=%s", (user['id'], class_id))
126 vote_exists = self.cursor.fetchone()
127 if vote_exists:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
128 self.notifyUser(screen_name, "You've already suggested this class")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
129 else:
130 self.cursor.execute("UPDATE classes SET score=score+1 WHERE id=%s", (class_id))
131 self.cursor.execute("INSERT INTO votes(follower, class) VALUES(%s, %s)", (user['id'], class_id))
132 if not new_class:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
133 self.notifyUser(screen_name, "We've jotted down your interest in this class, we'll tweet you if it goes live")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
134
135 elif init == 'add' and len(commands) > 1:
136 if commands[1].startswith('class') and len(commands) > 2:
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
137 for class_name in ' '.join(commands[2:]).split(','):
138 class_name = class_name.strip()
139 print "Adding class: "+class_name
140 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name))
141 class_data = self.cursor.fetchone()
142 class_id = None
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
143
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
144 if class_data == None:
145 # This class doesn't exist; can't do anything.
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
146 self.notifyUser(screen_name, "Bummer, this class doesn't exist yet. Suggest it by tweeting @findpassion suggest class class-name")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
147 return
148 else:
149 class_id = class_data[0]
150 if not class_data[1]: # Legit?
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
151 self.notifyUser(screen_name, "This class isn't legit. Show interest in it by tweeting @findpassion suggest class class-name")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
152 return
153
154 # At this point we know the class exists and is legit.
155 # Check if they've already added this class.
156 self.cursor.execute("SELECT follower FROM follower_classes WHERE follower=%s AND class=%s", (user['id'], class_id))
157 link_exists = self.cursor.fetchone()
158 if link_exists:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
159 self.notifyUser(screen_name, "You already have "+class_name+" listed")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
160 else:
161 self.cursor.execute("INSERT INTO follower_classes(follower, class) VALUES(%s, %s)", (user['id'], class_id))
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
162 self.notifyUser(screen_name, "We've jotted "+class_name+" down in your profile")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
163
164 elif init == 'remove' and len(commands) > 1:
165 if commands[1].startswith('class') and len(commands) > 2:
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
166 for class_name in ' '.join(commands[2:]).split(','):
167 class_name = class_name.strip()
168 print "Removing class: "+class_name
169 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name))
170 class_data = self.cursor.fetchone()
171 class_id = None
172
173 if class_data == None:
174 # This class doesn't exist; can't do anything.
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
175 self.notifyUser(screen_name, "That class doesn't exist")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
176 return
177 else:
178 class_id = class_data[0]
179
180 # At this point we know the class exists.
181 # Check if they've already added this class.
182 self.cursor.execute("SELECT follower FROM follower_classes WHERE follower=%s AND class=%s", (user['id'], class_id))
183 link_exists = self.cursor.fetchone()
184 if link_exists:
185 self.cursor.execute("DELETE FROM follower_classes WHERE follower=%s AND class=%s", (user['id'], class_id))
63a4845 Jeff Verkoeyen More minute text cleanup.
authored
186 self.notifyUser(screen_name, "We removed "+class_name+" from your profile")
8b4e5e2 Jeff Verkoeyen Add multi-class args to each command.
authored
187 else:
77908e3 Jeff Verkoeyen Clean up text, remove periods.
authored
188 self.notifyUser(screen_name, "You don't have "+class_name+" listed")
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
189
bde07cf Jeff Verkoeyen Add the ability to find people.
authored
190 elif init == 'find' and len(commands) > 1 or len(commands) >= 1:
191 if init == 'find':
192 commands = commands[1:]
193 for class_name in ' '.join(commands).split(','):
194 print "Looking for class: "+class_name
195 class_name = class_name.strip()
196 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name))
197 class_data = self.cursor.fetchone()
198
199 if class_data == None and class_name.endswith('s'):
200 self.cursor.execute("SELECT id, legit FROM classes WHERE name=%s", (class_name[:-1]))
201 class_data = self.cursor.fetchone()
202
203 if class_data == None:
204 self.notifyUser(screen_name, "That class doesn't exist")
205 else:
206 if class_data[1]: # Legit?
207 class_id = class_data[0]
208 self.cursor.execute("SELECT screen_name FROM follower_classes LEFT JOIN followers on follower = id WHERE class = %s AND available_for_hire=1", (class_id))
209 rows = self.cursor.fetchall()
210 if len(rows) > 0:
211 not_callee = []
212 for row in rows:
213 if not row[0] == screen_name:
214 not_callee.append(row[0])
215 if len(not_callee) > 0:
216 random.shuffle(not_callee)
217 self.notifyUser(screen_name, class_name+": @"+' @'.join(not_callee[:4]))
218 else:
219 self.notifyUser(screen_name, "You are currently the only listed person with this class")
220 else:
221 self.notifyUser(screen_name, "No available people with the class "+class_name)
222
223
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
224
225 needs_update = False
226 keys_to_update = []
227 values_to_update = []
228 for key in user:
229 if user[key] != updated_user[key]:
230 print " " + key + " '" + str(user[key]) + "' => '" + str(updated_user[key]) + "'"
231 needs_update = True
232 keys_to_update.append(key)
233 values_to_update.append(updated_user[key])
10f29f0 Jeff Verkoeyen Properly update the last tweet id and allow multiple class names.
authored
234
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
235 if needs_update:
236 print "Updating " + screen_name + "'s account..."
237 sql = "UPDATE followers SET "
238 for key in keys_to_update:
239 sql += key+"=%s "
240 sql += "WHERE id=%s"
0e0afcb Jeff Verkoeyen Don't close the db connection before we're done.
authored
241 print sql
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
242 values_to_update.append(user['id'])
243 self.cursor.execute(sql, values_to_update)
bde07cf Jeff Verkoeyen Add the ability to find people.
authored
244 self.existing_users[screen_name] = updated_user
be321d1 Jeff Verkoeyen Store updated users properly.
authored
245 self.updated_users[screen_name] = True
b649fe9 Jeff Verkoeyen Split the bot code into its own class.
authored
246
247
248 def dbToUser(self, row):
249 return {
250 'id': row[0],
251 'screen_name': row[1],
252 'available_for_hire': row[2],
253 'active': row[3],
254 'is_admin': row[4]}
255
256 def printStats(self):
257 twitterbot.StandardBot.printStats(self)
258 print "Available: "+str(self.available_users)
Something went wrong with that request. Please try again.