def add_new_account(username): address = generate_account() private = address["private"] address = address["account"] sql = "INSERT INTO accounts (username, private_key, address, minimum, auto_receive, silence, active, percentage, opt_in) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" val = ( username, private, address, to_raw(RECIPIENT_MINIMUM), True, False, False, 10, True, ) MYCURSOR.execute(sql, val) MYDB.commit() return { "username": username, "address": address, "private_key": private, "minimum": to_raw(RECIPIENT_MINIMUM), "silence": False, "balance": 0, "account_exists": True, }
def handle_silence(message): message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created username = str(message.author) add_history_record( username=str(message.author), action="silence", comment_or_message="message", comment_id=message.name, reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), ) parsed_text = parse_text(str(message.body)) if len(parsed_text) < 2: response = text.SILENCE["parse_error"] return response if parsed_text[1] == "yes": sql = "UPDATE accounts SET silence = TRUE WHERE username = %s " val = (username, ) MYCURSOR.execute(sql, val) response = text.SILENCE["yes"] elif parsed_text[1] == "no": sql = "UPDATE accounts SET silence = FALSE WHERE username = %s" val = (username, ) MYCURSOR.execute(sql, val) response = text.SILENCE["no"] else: response = text.SILENCE["yes_no"] MYDB.commit() return response
def handle_projects(message): """ Handles creation and updates of crowdfunding (NanoCenter) projects """ parsed_text = parse_text(str(message.body)) response = text.CROWD_FUNDING["projects"] if (str(message.author).lower() in DONATION_ADMINS + TIPBOT_OWNER) and len(parsed_text) > 2: sql = "INSERT INTO projects (project, address) VALUES(%s, %s) ON DUPLICATE KEY UPDATE address=%s" val = (parsed_text[1], parsed_text[2], parsed_text[2]) MYCURSOR.execute(sql, val) MYDB.commit() add_history_record( username=str(message.author), action="project", comment_text=str(message.body)[:255], comment_or_message="message", comment_id=message.name, ) sql = "SELECT project, address FROM projects" MYCURSOR.execute(sql) results = MYCURSOR.fetchall() for result in results: response += "%s %s \n" % (result[0], result[1]) return response
def auto_receive(): count = 0 MYCURSOR.execute("SELECT username, address, private_key FROM accounts") myresult = MYCURSOR.fetchall() addresses = [str(result[1]) for result in myresult] private_keys = [str(result[2]) for result in myresult] MYDB.commit() pendings = get_pendings(addresses, threshold=nano_to_raw(PROGRAM_MINIMUM)) # get any pending blocks from our address for address, private_key in zip(addresses, private_keys): # allow 5 transactions to be received per cycle. If the bot gets transaction spammed, at least it won't be # locked up receiving. if count >= 5: break try: if pendings["blocks"][address]: for sent_hash in pendings["blocks"][address]: # address, private_key, dictionary where the blocks are the keys open_or_receive_block(address, private_key, sent_hash) count += 1 if count >= 2: break except KeyError: pass except Exception as e: print(e)
def list_messages(): MYCURSOR.execute("SELECT * FROM messages") myresult = MYCURSOR.fetchall() MYDB.commit() for res in myresult: print(res) return myresult
def handle_create(message): message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created add_history_record( username=str(message.author), comment_or_message="message", reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), action="create", comment_id=message.name, comment_text=str(message.body)[:255], ) username = str(message.author) sql = "SELECT address FROM accounts WHERE username=%s" val = (username, ) MYCURSOR.execute(sql, val) result = MYCURSOR.fetchall() if len(result) is 0: address = tipper_functions.add_new_account(username)["address"] response = WELCOME_CREATE % (address, address) message_recipient = TIP_BOT_USERNAME subject = "send" message_text = "send 0.001 %s" % username sql = "INSERT INTO messages (username, subject, message) VALUES (%s, %s, %s)" val = (message_recipient, subject, message_text) MYCURSOR.execute(sql, val) MYDB.commit() # reddit.redditor(message_recipient).message(subject, message_text) else: response = text.ALREADY_EXISTS % (result[0][0], result[0][0]) return response
def query_sql(sql, val=None): if val: MYCURSOR.execute(sql, val) else: MYCURSOR.execute(sql) results = MYCURSOR.fetchall() MYDB.commit() return results
def init_projects(): MYCURSOR.execute( "CREATE TABLE projects (" "project VARCHAR(255) PRIMARY KEY, " "address VARCHAR(255)" ")" ) MYDB.commit()
def backup_keys(): sql = "SELECT username, address, private_key FROM accounts" MYCURSOR.execute(sql) results = MYCURSOR.fetchall() MYDB.commit() with open("../backup", "w") as f: for result in results: f.write(result[0] + "," + result[1] + "," + result[2] + "\n")
def exec_sql(sql, val): """ Makes sql stuff easier to mock, rather than mocking execute and fetchall :param sql: :param val: :return: """ MYCURSOR.execute(sql, val) MYDB.commit()
def list_returns(status=None): if status: MYCURSOR.execute("SELECT * FROM returns WHERE return_status=%s", (status,)) else: MYCURSOR.execute("SELECT * FROM returns") myresult = MYCURSOR.fetchall() MYDB.commit() for res in myresult: print(res) return myresult
def init_messages(): MYCURSOR.execute( "CREATE TABLE messages (" "id INT AUTO_INCREMENT PRIMARY KEY, " "username VARCHAR(255), " "subject VARCHAR(255), " "message VARCHAR(5000) " ")" ) MYDB.commit()
def init_subreddits(): MYCURSOR.execute( "CREATE TABLE subreddits (" "subreddit VARCHAR(255) PRIMARY KEY, " "reply_to_comments BOOL, " "footer VARCHAR(255), " "status VARCHAR(255) " ")" ) MYDB.commit()
def backup_history(): sql = "SELECT * FROM history" MYCURSOR.execute(sql) results = MYCURSOR.fetchall() MYDB.commit() with open("../backup_history", "w") as f: for result in results: for r in result: f.write(str(r) + ";") f.write("\n")
def add_subreddit( subreddit, reply_to_comments=True, footer="", status="friendly", minimum=PROGRAM_MINIMUM, ): sql = "INSERT INTO subreddits (subreddit, reply_to_comments, footer, status, minimum) VALUES (%s, %s, %s, %s, %s)" val = (subreddit, reply_to_comments, footer, status, minimum) MYCURSOR.execute(sql, val) MYDB.commit()
def all_pendings(threshold): threshold = float(threshold) MYCURSOR.execute("SELECT username, address FROM accounts") myresult = MYCURSOR.fetchall() usernames = [str(result[0]) for result in myresult] addresses = [str(result[1]) for result in myresult] MYDB.commit() pendings = tipper_rpc.get_pendings(addresses, threshold=to_raw(threshold)) for username, address in zip(usernames, addresses): if pendings["blocks"][address]: print(username, address, pendings["blocks"][address])
def handle_opt_in(message): add_history_record( username=str(message.author), action="opt-in", comment_or_message="message", comment_id=message.name, reddit_time=datetime.utcfromtimestamp( message.created_utc).strftime("%Y-%m-%d %H:%M:%S"), ) sql = "UPDATE accounts SET opt_in = TRUE WHERE username = %s" MYCURSOR.execute(sql, (str(message.author), )) MYDB.commit() response = text.OPT_IN return response
def total_funds(): MYCURSOR.execute("SELECT username, address FROM accounts") myresult = MYCURSOR.fetchall() usernames = [str(result[0]) for result in myresult] addresses = [str(result[1]) for result in myresult] MYDB.commit() balance = 0 for username, address in zip(usernames, addresses): balance new_balance = tipper_rpc.check_balance(address) temp_balance = new_balance[0] / 10**30 + new_balance[1] / 10**30 if temp_balance >= 50: print(username, temp_balance, address) balance += temp_balance print("Total Nano: ", balance)
def send_pm(recipient, subject, body, bypass_opt_out=False): opt_in = True # If there is not a bypass to opt in, check the status if not bypass_opt_out: sql = "SELECT opt_in FROM accounts WHERE username=%s" MYCURSOR.execute(sql, (recipient,)) opt_in = MYCURSOR.fetchall()[0][0] MYDB.commit() # if the user has opted in, or if there is an override to send the PM even if they have not if opt_in or not bypass_opt_out: sql = "INSERT INTO messages (username, subject, message) VALUES (%s, %s, %s)" val = (recipient, subject, body) MYCURSOR.execute(sql, val) MYDB.commit()
def handle_delete_project(message): parsed_text = parse_text(str(message.body)) if ((str(message.author) == TIPBOT_OWNER) or (str(message.author).lower() == "rockmsockmjesus")) and len(parsed_text) > 1: sql = "DELETE FROM projects WHERE project=%s" val = (parsed_text[1], ) MYCURSOR.execute(sql, val) MYDB.commit() response = text.CROWD_FUNDING["projects"] sql = "SELECT project, address FROM projects" MYCURSOR.execute(sql) results = MYCURSOR.fetchall() for result in results: response += "%s %s \n" % (result[0], result[1]) return response
def handle_opt_in(message): add_history_record( username=str(message.author), action="opt-in", comment_or_message="message", comment_id=message.name, reddit_time=datetime.utcfromtimestamp( message.created_utc).strftime("%Y-%m-%d %H:%M:%S"), ) sql = "UPDATE accounts SET opt_in = TRUE WHERE username = %s" MYCURSOR.execute(sql, (str(message.author), )) MYDB.commit() response = ( "Welcome back! You have opted back in. Your account will be restored with the same address, " "though any Nano you had may have already been returned or donated already." ) return response
def init_returns(): MYCURSOR.execute( "CREATE TABLE returns (" "id INT AUTO_INCREMENT PRIMARY KEY, " "username VARCHAR(255), " "reddit_time TIMESTAMP, " "sql_time TIMESTAMP, " "recipient_username VARCHAR(255), " "recipient_address VARCHAR(255), " "amount VARCHAR(255), " "hash VARCHAR(255), " "comment_id VARCHAR(255), " "return_status VARCHAR(255), " "history_id INT" ")" ) MYDB.commit()
def add_history_record( username=None, action=None, sql_time=None, address=None, comment_or_message=None, recipient_username=None, recipient_address=None, amount=None, hash=None, comment_id=None, notes=None, reddit_time=None, comment_text=None, subreddit=None, ): if sql_time is None: sql_time = time.strftime("%Y-%m-%d %H:%M:%S") sql = ( "INSERT INTO history (username, action, sql_time, address, comment_or_message, recipient_username, " "recipient_address, amount, hash, comment_id, notes, reddit_time, comment_text, return_status, subreddit) " "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" ) val = ( username, action, sql_time, address, comment_or_message, recipient_username, recipient_address, amount, hash, comment_id, notes, reddit_time, comment_text, None, subreddit, ) # todo make sure the row id is atomic MYCURSOR.execute(sql, val) MYDB.commit() return MYCURSOR.lastrowid
def init_accounts(): MYCURSOR.execute( "CREATE TABLE accounts (" "username VARCHAR(255) PRIMARY KEY, " "address VARCHAR(255), " "private_key VARCHAR(255), " "key_released BOOL, " "minimum VARCHAR(255), " "notes VARCHAR(255), " "auto_receive BOOL, " "silence BOOL, " "active BOOL, " "percentage VARCHAR(255), " "opt_in BOOL" ")" ) MYDB.commit()
def handle_opt_out(message): add_history_record( username=str(message.author), action="opt-out", comment_or_message="message", comment_id=message.name, reddit_time=datetime.utcfromtimestamp( message.created_utc).strftime("%Y-%m-%d %H:%M:%S"), ) sql = "UPDATE accounts SET opt_in = FALSE WHERE username = %s" MYCURSOR.execute(sql, (str(message.author), )) MYDB.commit() response = ( "You have opted-out and I promise not to bother you anymore.\n\nReturnable Nano will be returned " "to the tippers, and the remaining balance will be donated to the tipbot fund.\n\nIf this was in " "error, please respond immediately with the text `opt-in`.") return response
def handle_comment(message): response = send_from_comment(message) response_text = text.make_response_text(message, response) # check if subreddit is untracked or silent. If so, PM the users. if response["subreddit_status"] in ["silent", "hostile"]: message_recipient = str(message.author) if response["status"] < 100: subject = "Your Tip Was Successful" else: subject = "You Tip Did Not Go Through" message_text = response_text + text.COMMENT_FOOTER sql = "INSERT INTO messages (username, subject, message) VALUES (%s, %s, %s)" val = (message_recipient, subject, message_text) MYCURSOR.execute(sql, val) MYDB.commit() else: message.reply(response_text + text.COMMENT_FOOTER)
def init_history(): MYCURSOR.execute( "CREATE TABLE history (" "id INT AUTO_INCREMENT PRIMARY KEY, " "username VARCHAR(255), " "action VARCHAR(255), " "reddit_time TIMESTAMP, " "sql_time TIMESTAMP, " "address VARCHAR(255), " "comment_or_message VARCHAR(255), " "recipient_username VARCHAR(255), " "recipient_address VARCHAR(255), " "amount VARCHAR(255), " "hash VARCHAR(255), " "comment_id VARCHAR(255), " "comment_text VARCHAR(255), " "notes VARCHAR(255), " "return_status VARCHAR(255)" ")" ) MYDB.commit()
def handle_silence(message): message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created username = str(message.author) add_history_record( username=str(message.author), action="silence", comment_or_message="message", comment_id=message.name, reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), ) parsed_text = parse_text(str(message.body)) if len(parsed_text) < 2: response = ("I couldn't parse your command. I was expecting 'silence " "<yes/no>'. Be sure to check your spacing.") return response if parsed_text[1] == "yes": sql = "UPDATE accounts SET silence = TRUE WHERE username = %s " val = (username, ) MYCURSOR.execute(sql, val) response = ("Silence set to 'yes'. You will no longer receive tip " "notifications or be tagged by the bot.") elif parsed_text[1] == "no": sql = "UPDATE accounts SET silence = FALSE WHERE username = %s" val = (username, ) MYCURSOR.execute(sql, val) response = ( "Silence set to 'no'. You will receive tip notifications and be " "tagged by the bot in replies.") else: response = ( "I did not see 'no' or 'yes' after 'silence'. If you did type " "that, check your spacing.") MYDB.commit() return response
def add_return_record( username=None, reddit_time=None, sql_time=None, recipient_username=None, recipient_address=None, amount=None, hash=None, comment_id=None, return_status=None, history_id=None, ): if sql_time is None: sql_time = time.strftime("%Y-%m-%d %H:%M:%S") sql = ( "INSERT INTO returns (username, reddit_time, sql_time, recipient_username," " recipient_address, amount, hash, comment_id, return_status, history_id)" " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" ) val = ( username, reddit_time, sql_time, recipient_username, recipient_address, amount, hash, comment_id, return_status, history_id, ) MYCURSOR.execute(sql, val) MYDB.commit() return MYCURSOR.lastrowid
def handle_create(message): message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created add_history_record( username=str(message.author), comment_or_message="message", reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), action="create", comment_id=message.name, comment_text=str(message.body)[:255], ) username = str(message.author) sql = "SELECT address FROM accounts WHERE username=%s" val = (username, ) MYCURSOR.execute(sql, val) result = MYCURSOR.fetchall() if len(result) is 0: address = tipper_functions.add_new_account(username) response = WELCOME_CREATE % (address, address) message_recipient = TIP_BOT_USERNAME subject = "send" message_text = "send 0.001 %s" % username sql = "INSERT INTO messages (username, subject, message) VALUES (%s, %s, %s)" val = (message_recipient, subject, message_text) MYCURSOR.execute(sql, val) MYDB.commit() # reddit.redditor(message_recipient).message(subject, message_text) else: response = ( "It looks like you already have an account. In any case it is now " "**active**. Your Nano address is %s." "\n\nhttps://nanocrawler.cc/explorer/account/%s" % (result[0][0], result[0][0])) return response