Skip to content

Instantly share code, notes, and snippets.

@sjnovick
Created July 3, 2019 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjnovick/964120942605bbbfa517312228adfa02 to your computer and use it in GitHub Desktop.
Save sjnovick/964120942605bbbfa517312228adfa02 to your computer and use it in GitHub Desktop.
# flairbot.py
#
# Script to automate the process of awarding user feedback (aka "rep" or "flair") for
# positive transactions conducted on a reddit-based buying and selling community.
#
# sjnovick 2019
#
#
# Constraints that must be met before flair is awarded:
#
# Scenario 1 - The top level comment...
# 1 - has a target user
# 2 - is not authored by the target user
# 3 - has a feedback keyword
# 4 - has a permalink
# 5 - is authored by the buyer
#
# Scenario 2 - The top level comment...
# 1 - has a target user
# 2 - is not authored by the target user
# 3 - has a feedback keyword
# 4 - has a permalink
# 5 - is confirmed by the target user
#
# Scenario 3 - The top level comment...
# 1 - has a target user
# 2 - is not authored by the target user
# 3 - has a feedback keyword
# 4 - has a discord keyword
# 5 - is confirmed by the target user
#
# If contraint scenario is met:
# 1 - Get both users original flair
# 2 - Determine both users new flair (increment by 1)
# 3 - Set both users new flair
# 4 - Reply to top level comment
# 5 - Remove top level comment
import praw
import pprint
import re
import datetime
import sqlite3
threadID = 'redacted'
reddit = praw.Reddit('bot')
subreddit = reddit.subreddit('redacted')
submission = reddit.submission(id=threadID)
submission.comments.replace_more(limit=None)
db = sqlite3.connect('/home/user/flairbot/db/flairbot.db')
def user_exists(user): # verifies that a legit reddit account exists
exists = True
try:
id = reddit.redditor(user).id
except:
exists = False
return exists
def check_target_user(top_level_comment): # looks for a username in a comment. if a user is found, returns redditor object targetUser
author = top_level_comment.author
#old: u\/[A-Za-z0-9\\\_-]+
#new: (?i)(?<=u/)[a-z0-9\\\_-]+(?=\\n\\n)
userMatch = re.search('(?i)(?<=u/)[a-z0-9\\\_-]+', top_level_comment.body)
if userMatch:
userMatch = userMatch.group(0)
#userMatch = userMatch.strip('/u ')
userMatch = re.sub(r'\r?\n.*', '',userMatch)
translation_table = dict.fromkeys(map(ord, '\\'), None)
userMatch = userMatch.translate(translation_table)
exists = user_exists(userMatch)
if exists:
targetUser = reddit.redditor(userMatch)
return targetUser
else:
return False
return False
return False
def check_author_is_not_target_user(author,targetUser): # checks that the author of the top level comment, and the target user are not the same
if author != targetUser:
return True
return False
def check_feedback(top_level_comment): # looks for "positive" keyword in a comment. if found, returns "positive"
feedback=""
flairMatch = re.search("(?i)positive",top_level_comment.body)
if flairMatch:
feedback = flairMatch.group(0)
return feedback
return False
def check_buyer(top_level_comment): # looks for "buyer" keyword in a comment. if found, returns authorIsBuyer = True
#old: ((im|i'm|Im|I'm)\s)the\s[bB]uyer|(?<=[bB]uyer)\.]
#new: (?i)^((im|i'm|i’m|i\sam|i\swas)\s)the\sbuyer
buyerMatch = re.search("(?i)((im|i'm|i’m|i\sam|i\swas)\s)the\sbuyer",top_level_comment.body)
if buyerMatch:
authorIsBuyer=True
return authorIsBuyer
return False
def check_permalink(top_level_comment): # looks for a permalink in comment. if found, returns the permalink
permaMatch = re.search("https:\/\/(www.|old.|)reddit.com\/r\/(?i)redacted\/.*",top_level_comment.body)
if permaMatch:
permaMatch = permaMatch.group(0)
return permaMatch
return False
def check_discord(top_level_comment): # looks for "discord" keyword in a comment. if found, returns discord = True
discordMatch = re.search("(?i)discord",top_level_comment.body)
if discordMatch:
discordMatch = discordMatch.group(0)
return discordMatch
return False
def check_confirmation(comment,targetUser): # looks thru all replies to a top level comment for a reply from # targetUser with a "confirmed" keyword.
confirmation = False # if found, returns confirmation = True
if comment.replies:
comment.replies.replace_more(limit=None)
for reply in comment.replies:
if reply.author == targetUser:
#old: (?i)([Cc]onfirm|(?<=[Cc]onfirm)ed)|([P|p]ositive)
#new: (?i)^confirm|positive
confirmMatch = re.search("(?i)^confirm|positive",reply.body)
if confirmMatch:
confirmation = True
break
return confirmation
return confirmation
def check_removed(comment): # check if comment has been removed by a mod, if so return True
if comment.banned_at_utc == None: return False
return True
def check_mod_replied(comment): # check if comment has been replied to by a mod, if so return True
comment.replies.replace_more(limit=None)
if comment.replies:
for reply in comment.replies:
mods=["redacted"]
if reply.author in mods: return True
return False
def check_mod_authored(comment): # check if comment is authored by certain excluded mods, if so return True
mods=["redacted"]
if comment.author in mods: return True
return False
def get_og_flair(user): # gets current subreddit flair for user. if none, returns 0. if it starts with "+" or "-", returns int
ogFlair = None
success = False
ogFlair = next(subreddit.flair(user))
ogFlair = ogFlair['flair_text']
if ogFlair == None or ogFlair == '0 Trades' or ogFlair == 'New Account':
ogFlair = 0
success = True
return ogFlair,success
posMatch = re.search('^\+\d*', ogFlair)
if posMatch:
ogFlair = posMatch.group(0)
ogFlair = ogFlair[1:]
ogFlair = int(ogFlair)
success = True
return ogFlair,success
negMatch = re.search('^\-\d*', ogFlair)
if negMatch:
ogFlair = negMatch.group(0)
ogFlair = int(ogFlair)
success = True
return ogFlair,success
return ogFlair,success
def do_math(ogFlair): # adds +1 to ints, if >30 changes flair to ">30 Trusted Trader"
newFlair = None
newSuccess = False
if type(ogFlair) is int:
newFlair = ogFlair + 1
if newFlair > 0 and newFlair < 31:
newFlair = str(newFlair)
newFlair = "+" + newFlair
newSuccess = True
return newFlair,newSuccess
elif newFlair > 30:
newFlair = str(newFlair)
newFlair = ">30 Trusted Trader"
newSuccess = True
return newFlair,newSuccess
return newFlair,newSuccess
return newFlair,newSuccess
def set_flair(user): # edits the flair for user
ogFlair,ogSuccess = get_og_flair(user)
newFlair,newSuccess = do_math(ogFlair)
if ogSuccess and newSuccess:
print (" ! Flairing:", user.name)
subreddit.flair.set(user,newFlair)
overallSuccess = True
return overallSuccess,ogFlair,newFlair
else:
overallSuccess = False
return overallSuccess,ogFlair,newFlair
def remove_comment(top_level_comment): # removes the top level comment
print (" * Removing:", top_level_comment.id)
top_level_comment.mod.remove()
def reply(top_level_comment): # replies to the lop level comment, states flaired
print (" * Replying:", top_level_comment.id)
top_level_comment.reply("flaired")
def insert_flairLog(dateParsed, dateSubmitted, threadID, commentID, author, targetUser, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision, authorOgFlair, authorNewFlair, targetOgFlair, targetNewFlair):
print (" * Writing to flairLog:", top_level_comment.id)
cursor = db.cursor()
cursor.execute('''INSERT INTO flairLog (date_parsed, date_submitted, thread_id, comment_id, author, targetUser, feedback, permalink, notTargetUser, authorIsBuyer, confirmed, decision, authorOld, authorNew, targetOld, targetNew)
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? );''', (dateParsed, dateSubmitted, threadID, commentID, author, targetUser, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision, authorOgFlair, authorNewFlair, targetOgFlair, targetNewFlair))
db.commit()
def insert_skipLog(dateParsed, dateSubmitted, threadID, commentID, author, targetUser, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision):
print (" Writing to skipLog:", top_level_comment.id)
cursor = db.cursor()
cursor.execute('''INSERT INTO skipLog (date_parsed, date_submitted, thread_id, comment_id, author, targetUser, feedback, permalink, notTargetUser, authorIsBuyer, confirmed, decision)
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? );''', (dateParsed, dateSubmitted, threadID, commentID, author, targetUser, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision))
db.commit()
# main loop
# loops thru all top level comments in the submission
dateParsed = datetime.datetime.utcnow().isoformat(' ', 'seconds')
print(">>>>> Starting run at", dateParsed)
i=0
for top_level_comment in submission.comments:
removed = check_removed(top_level_comment)
modAuthored = check_mod_authored(top_level_comment)
#modReplied = check_mod_replied(top_level_comment)
dateSubmitted = datetime.datetime.utcfromtimestamp(top_level_comment.created_utc).isoformat(' ', 'seconds')
if not removed and not modAuthored:
#and not modReplied:
author = top_level_comment.author
authorIsBuyer = check_buyer(top_level_comment)
targetUser = check_target_user(top_level_comment)
authorIsNotTargetUser = check_author_is_not_target_user(author,targetUser)
feedback = check_feedback(top_level_comment)
permalink = check_permalink(top_level_comment)
discord = check_discord(top_level_comment)
confirmation = check_confirmation(top_level_comment,targetUser)
decision = 0
if targetUser and authorIsNotTargetUser and feedback and permalink and authorIsBuyer: # Constraint Scenario 1
decision = 1
authorFlairSuccess,authorOgFlair,authorNewFlair = set_flair(author)
targetFlairSuccess,targetOgFlair,targetNewFlair = set_flair(targetUser)
reply(top_level_comment)
remove_comment(top_level_comment)
insert_flairLog(dateParsed, dateSubmitted, threadID, top_level_comment.id, author.name, targetUser.name, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision, authorOgFlair, authorNewFlair, targetOgFlair, targetNewFlair)
elif targetUser and authorIsNotTargetUser and feedback and permalink and confirmation: # Constraint Scenario 2
decision = 2
authorFlairSuccess,authorOgFlair,authorNewFlair = set_flair(author)
targetFlairSuccess,targetOgFlair,targetNewFlair = set_flair(targetUser)
reply(top_level_comment)
remove_comment(top_level_comment)
insert_flairLog(dateParsed, dateSubmitted, threadID, top_level_comment.id, author.name, targetUser.name, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision, authorOgFlair, authorNewFlair, targetOgFlair, targetNewFlair)
elif targetUser and authorIsNotTargetUser and feedback and discord and confirmation: # Constraint Scenario 3
decision = 3
authorFlairSuccess,authorOgFlair,authorNewFlair = set_flair(author)
targetFlairSuccess,targetOgFlair,targetNewFlair = set_flair(targetUser)
reply(top_level_comment)
remove_comment(top_level_comment)
insert_flairLog(dateParsed, dateSubmitted, threadID, top_level_comment.id, author.name, targetUser.name, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision, authorOgFlair, authorNewFlair, targetOgFlair, targetNewFlair)
else: # Constraints not met
decision = 0
if author != None:
author = author.name
if targetUser != False:
targetUser = targetUser.name
insert_skipLog(dateParsed, dateSubmitted, threadID, top_level_comment.id, author, targetUser, feedback, permalink, authorIsNotTargetUser, authorIsBuyer, confirmation, decision)
i=i+1
db.close()
date = datetime.datetime.utcnow().isoformat(' ', 'seconds')
print(">>>>> Finished at", date)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment