replicator/bots-setup.py

566 líneas
13 KiB
Python
Original Vista normal Històric

2022-02-16 18:43:30 +01:00
import getpass
import os
import time
2022-02-16 18:43:30 +01:00
import sys
import psycopg2
from mastodon import Mastodon
from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout, MastodonAPIError, MastodonIllegalArgumentError
import uuid
import requests
from prettytable import PrettyTable
2022-02-16 18:43:30 +01:00
import pdb
menu_options = {
1: 'New Bot',
2: 'Delete Bot',
3: 'Activate Bot',
4: 'Deactivate Bot',
5: 'List Bots',
6: 'Exit',
}
def print_menu():
for key in menu_options.keys():
print (key, '-', menu_options[key] )
2022-02-20 23:23:28 +01:00
def get_config():
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
# Load configuration from config file
config_filepath = "config/db_config.txt"
replicator_db = get_db_params("replicator_db", config_filepath)
replicator_db_user = get_db_params("replicator_db_user", config_filepath)
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
return (config_filepath, replicator_db, replicator_db_user)
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
def check_db_conn():
2022-02-16 18:43:30 +01:00
try:
2022-02-20 23:23:28 +01:00
conn = None
2022-02-16 18:43:30 +01:00
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
2022-02-20 23:23:28 +01:00
except (Exception, psycopg2.DatabaseError) as error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.exit("Exiting. Run 'python db-setup' again")
2022-02-16 18:43:30 +01:00
def check_host(url):
host_exists = False
try:
r = requests.get(f'https://{url}')
host_exists = True
except requests.exceptions.RequestException as error:
print(f'\n{url}: {error}')
time.sleep(3)
return host_exists
2022-02-20 23:23:28 +01:00
class Bot:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
name = "Bot"
2022-02-16 18:43:30 +01:00
def __init__(self):
2022-02-16 18:43:30 +01:00
self.hostname = input("\nEnter Mastodon/Pleroma hostname: ")
self.software = input("Server software (mastodon or pleroma)? ")
self.username = input(f'User name, ex. user@{self.hostname}? ')
self.password = getpass.getpass("User password? ")
self.app_name = 'replicator'
self.twitter_username = input(f'Twitter username (ex. jack)? ')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
def log_in(self):
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
token = ''
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
try:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
response = Mastodon.create_app(
self.app_name,
scopes=["read","write"],
to_file=None,
api_base_url=self.hostname
)
client_id = response[0]
client_secret = response[1]
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
mastodon = Mastodon(client_id = client_id, client_secret = client_secret, api_base_url = self.hostname)
token = mastodon.log_in(
self.username,
self.password,
scopes = ["read", "write"],
to_file = None
)
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
print('Log in succesful!')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except MastodonIllegalArgumentError as i_error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(i_error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except MastodonNetworkError as n_error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(n_error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except MastodonReadTimeout as r_error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(r_error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except MastodonAPIError as a_error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(a_error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
finally:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
return (client_id, client_secret, token)
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
def check_account(self):
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
is_duplicate = False
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sql = 'select username from maccounts where username=(%s)'
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn = None
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
try:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
cur = conn.cursor()
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
cur.execute(sql, (self.username,))
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
row = cur.fetchone()
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
if row != None:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
is_duplicate = True
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except (Exception, psycopg2.DatabaseError) as error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
check_error = error.pgcode
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
finally:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
if conn is not None:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn.close()
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
return is_duplicate
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
def save_account(self, client_id, client_secret, token):
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
bot_uuid = str(uuid.uuid4())
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
save_error = None
2022-02-16 18:43:30 +01:00
mastodon_sql = 'INSERT INTO maccounts (bot_id, hostname, username, client_id, client_secret, client_token, hostname_soft) VALUES (%s,%s,%s,%s,%s,%s,%s)'
2022-02-16 18:43:30 +01:00
twitter_sql = 'INSERT INTO taccounts (bot_id, username) VALUES (%s,%s)'
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn = None
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
try:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
cur = conn.cursor()
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
cur.execute(mastodon_sql, (bot_uuid, self.hostname, self.username, client_id, client_secret, token, self.software))
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
cur.execute(twitter_sql, (bot_uuid, self.twitter_username))
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
conn.commit()
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
except (Exception, psycopg2.DatabaseError) as error:
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
save_error = error.pgcode
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
sys.stdout.write(f'\n{str(error)}\n')
2022-02-16 18:43:30 +01:00
2022-02-20 23:23:28 +01:00
finally:
if conn is not None:
conn.close()
return save_error
2022-02-16 18:43:30 +01:00
class GetBot:
name = "GetBot"
def __init__(self):
self.twitter_username = input(f'Twitter username? ')
def delete_account(self):
del_error = None
twitter_sql = 'SELECT bot_id from taccounts where username=(%s)'
twitter_del_sql = 'DELETE FROM taccounts WHERE username=(%s)'
mastodon_del_sql = 'DELETE FROM maccounts WHERE bot_id=(%s)'
conn = None
try:
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
cur = conn.cursor()
cur.execute(twitter_sql, (self.twitter_username,))
row = cur.fetchone()
if row != None:
delete_it = confirm_deletion(self.twitter_username)
if delete_it:
bot_id = row[0]
cur.execute(twitter_del_sql, (self.twitter_username,))
cur.execute(mastodon_del_sql, (bot_id,))
conn.commit()
print(f'{self.twitter_username} had been deleted.')
time.sleep(2)
else:
print(f'{self.twitter_username} does not exists!')
time.sleep(2)
except (Exception, psycopg2.DatabaseError) as error:
del_error = error.pgcode
sys.stdout.write(f'\n{str(error)}\n')
finally:
if conn is not None:
conn.close()
return (del_error)
def activate_account(self):
twitter_sql = 'SELECT bot_id from taccounts where username=(%s)'
activate_sql = 'update maccounts set active = True WHERE bot_id=(%s)'
conn = None
try:
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
cur = conn.cursor()
cur.execute(twitter_sql, (self.twitter_username,))
row = cur.fetchone()
if row != None:
cur.execute(activate_sql, (row[0],))
conn.commit()
print(f'{self.twitter_username} had been activated')
time.sleep(2)
else:
print(f'{self.twitter_username} is not in the database')
except (Exception, psycopg2.DatabaseError) as error:
activate_error = error.pgcode
sys.stdout.write(f'\n{str(activate_error)}\n')
finally:
if conn is not None:
conn.close()
def deactivate_account(self):
twitter_sql = 'SELECT bot_id from taccounts where username=(%s)'
deactivate_sql = 'update maccounts set active = False WHERE bot_id=(%s)'
conn = None
try:
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
cur = conn.cursor()
cur.execute(twitter_sql, (self.twitter_username,))
row = cur.fetchone()
if row != None:
cur.execute(deactivate_sql, (row[0],))
conn.commit()
print(f'{self.twitter_username} had been deactivated')
time.sleep(2)
else:
print(f'{self.twitter_username} is not in the database')
except (Exception, psycopg2.DatabaseError) as error:
activate_error = error.pgcode
sys.stdout.write(f'\n{str(activate_error)}\n')
finally:
if conn is not None:
conn.close()
def print(self):
print(f'\nBot found: {self.twitter_username}\n')
def confirm_deletion(twitter_username):
answer = ''
while (answer != 'Yes' and answer != 'No'):
2022-03-22 12:27:20 +01:00
answer = input(f'Are you sure deleting {twitter_username} (Yes or No)?: ')
if answer == 'Yes':
print('Ok, deleting it...')
delete_it = True
if answer == 'No':
print('Doing nothing.')
delete_it = False
return delete_it
def list_bots():
bots_list = []
t_usernames_lst = []
mastodon_sql = 'SELECT bot_id, hostname, username, hostname_soft, active FROM maccounts'
twitter_sql = 'SELECT username from taccounts where bot_id=(%s)'
conn = None
try:
conn = psycopg2.connect(database = replicator_db, user = replicator_db_user, password = "", host = "/var/run/postgresql", port = "5432")
cur = conn.cursor()
cur.execute(mastodon_sql)
rows = cur.fetchall()
for row in rows:
cur.execute(twitter_sql, (row[0],))
username_row = cur.fetchone()
t_usernames_lst.append(username_row[0])
bots_list.append(row)
except (Exception, psycopg2.DatabaseError) as error:
get_error = error.pgcode
sys.stdout.write(f'\n{str(error)}\n')
finally:
if conn is not None:
conn.close()
return (bots_list, t_usernames_lst)
2022-02-16 18:43:30 +01:00
def get_db_params( parameter, file_path ):
if not os.path.isfile(file_path):
print("File %s not found, exiting."%file_path)
sys.exit(0)
# Find parameter in file
with open( file_path ) as f:
for line in f:
if line.startswith( parameter ):
return line.replace(parameter + ":", "").strip()
# Cannot find parameter, exit
print(file_path + " Missing parameter %s "%parameter)
sys.exit(0)
###############################################################################
# main
if __name__ == '__main__':
while(True):
2022-02-16 18:43:30 +01:00
print('\n')
2022-02-16 18:43:30 +01:00
print_menu()
2022-02-16 18:43:30 +01:00
option = ''
2022-02-16 18:43:30 +01:00
try:
2022-02-16 18:43:30 +01:00
option = int(input('\nEnter your choice: '))
2022-02-16 18:43:30 +01:00
except:
2022-02-16 18:43:30 +01:00
print('\nWrong input. Please enter a number between 1 and 4.\n')
2022-02-16 18:43:30 +01:00
if option == 1:
2022-02-16 18:43:30 +01:00
config_filepath, replicator_db, replicator_db_user = get_config()
2022-02-16 18:43:30 +01:00
check_db_conn()
2022-02-16 18:43:30 +01:00
myBot = Bot()
2022-02-16 18:43:30 +01:00
host_exists = check_host(myBot.hostname)
2022-02-16 18:43:30 +01:00
if host_exists:
is_duplicate = myBot.check_account()
if is_duplicate:
print(f'\nBot account already exist!\n')
time.sleep(3)
else:
client_id, client_secret, token = myBot.log_in()
if len(token) > 0:
save_error = myBot.save_account(client_id, client_secret, token)
if save_error == None:
print(f'Bot added!')
time.sleep(3)
else:
if save_error == '423505':
print(f'error: {save_error}')
elif option == 2:
config_filepath, replicator_db, replicator_db_user = get_config()
check_db_conn()
getbot = GetBot()
getbot.delete_account()
elif option == 3:
config_filepath, replicator_db, replicator_db_user = get_config()
check_db_conn()
getbot = GetBot()
getbot.activate_account()
elif option == 4:
config_filepath, replicator_db, replicator_db_user = get_config()
check_db_conn()
getbot = GetBot()
getbot.deactivate_account()
elif option == 5:
config_filepath, replicator_db, replicator_db_user = get_config()
check_db_conn()
bots_list, t_usernames_lst = list_bots()
print_table = PrettyTable()
print_table.field_names = ['No.','Twitter username', 'bot account', 'host', 'host software', 'active']
i = 0
for bot in bots_list:
print_table.add_row([str(i+1), t_usernames_lst[i], bot[2], bot[1], bot[3], bot[4]])
i += 1
print(print_table)
print(f'Total: {len(bots_list)}')
elif option == 6:
2022-02-16 18:43:30 +01:00
print('Bye!')
exit()
2022-02-16 18:43:30 +01:00