Comparar commits
15 commits
Autor | SHA1 | Fecha | |
---|---|---|---|
spla | 67e239ebad | ||
spla | 700ad081b4 | ||
spla | 60a5be7b3d | ||
spla | 05f097a048 | ||
spla | 8637160b53 | ||
spla | 92bcd577d5 | ||
spla | 130fbdbdbd | ||
spla | 49b3f1c6d3 | ||
spla | c7b5deb32a | ||
spla | 8710dee852 | ||
spla | e6ae2104a4 | ||
spla | 17e74f8517 | ||
spla | 9fbc5a6d44 | ||
spla | 7be37273fc | ||
spla | 97445baf33 |
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Mail your Mastodon server inactive users and track their feedback.
|
Mail your Mastodon server inactive users and track their feedback.
|
||||||
|
|
||||||
This code written in Python get all more than a year inactive users from Mastodon's database and email them with the subject and message of your choice.
|
This code written in Python get all more than six months inactive users from your Mastodon's database and email them with the subject and message of your choice.
|
||||||
Then, inactive users data is stored into new created Postgresql database to track feedback and status.
|
Then, inactive users data is stored into new created Postgresql database to track feedback and status.
|
||||||
Run mailing.py periodically to catch 'new' inactive users and update the elapsed days of the already emailed ones.
|
Run mailing.py periodically to catch 'new' inactive users and update the elapsed days of the already emailed ones.
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ Run mailing.py periodically to catch 'new' inactive users and update the elapsed
|
||||||
- **Python 3**
|
- **Python 3**
|
||||||
- Postgresql server
|
- Postgresql server
|
||||||
- Mastodon server (admin)
|
- Mastodon server (admin)
|
||||||
- Everything else at the top of `mailing.py`!
|
|
||||||
|
|
||||||
### Usage:
|
### Usage:
|
||||||
|
|
||||||
|
@ -21,11 +20,11 @@ Within Python Virtual Environment:
|
||||||
|
|
||||||
2. Run `python setup.py` to set your SMTP parameters and desired email subject. Also set your Mastodon's full path. They will be saved to `secrets/secrets.txt` for further use.
|
2. Run `python setup.py` to set your SMTP parameters and desired email subject. Also set your Mastodon's full path. They will be saved to `secrets/secrets.txt` for further use.
|
||||||
|
|
||||||
3. Run `python mailing.py` to start emailing your inactive users (`last_sign_in_at` column older than a year). Their username, account_id, email, delivery status (True if successful) and delivery date will be written to Postgresql database. There is another column, `deleted`, False by default. Will be useful to track deleted/not deleted inactive users if you choose to do so.
|
3. Run `python mailing.py` to start emailing your inactive users (`current_sign_in_at` column older than six months). Their username, account_id, email, delivery status (True if successful) and delivery date will be written to Postgresql database. There is another column, `deleted`, False by default. Will be useful to track deleted/not deleted inactive users if you choose to do so.
|
||||||
|
|
||||||
4. Use your favourite scheduling method to set mailing.py to run regularly. Column 'elapsed_days' of mailing's database will be updated so you can decide actions after some time.
|
4. Use your favourite scheduling method to set mailing.py to run regularly. Column 'elapsed_days' of mailing's database will be updated so you can decide actions after some time.
|
||||||
|
|
||||||
5. Run `python delete_inactives.py` to delete all inactive users after 30 days period from the warning email.
|
5. Run `python delete_inactives.py` to delete all inactive users who replied yes to deletion and all the rest with no feedback after 31 days period from the warning email.
|
||||||
|
|
||||||
6. Run `python edit_status.py` to set True or False any of following `mailing_db_table` columns: `to_be_deleted`, `feedback` and `recipient_error`. Useful after emailed user's feedback.
|
6. Run `python edit_status.py` to set True or False any of following `mailing_db_table` columns: `to_be_deleted`, `feedback` and `recipient_error`. Useful after emailed user's feedback.
|
||||||
|
|
||||||
|
|
190
db-setup.py
190
db-setup.py
|
@ -8,7 +8,19 @@ import psycopg2
|
||||||
from psycopg2 import sql
|
from psycopg2 import sql
|
||||||
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
|
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
|
||||||
# Returns the parameter from the specified file
|
def get_config():
|
||||||
|
|
||||||
|
# Load configuration from config file
|
||||||
|
config_filepath = "config/db_config.txt"
|
||||||
|
mastodon_db = get_parameter("mastodon_db", config_filepath)
|
||||||
|
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath)
|
||||||
|
mailing_db = get_parameter("mailing_db", config_filepath)
|
||||||
|
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
||||||
|
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
||||||
|
inactive_days = get_parameter("inactive_days", config_filepath)
|
||||||
|
|
||||||
|
return (mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table)
|
||||||
|
|
||||||
def get_parameter( parameter, file_path ):
|
def get_parameter( parameter, file_path ):
|
||||||
# Check if secrets file exists
|
# Check if secrets file exists
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
|
@ -27,28 +39,84 @@ def get_parameter( parameter, file_path ):
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def write_parameter( parameter, file_path ):
|
def write_parameter( parameter, file_path ):
|
||||||
print("Setting up mailing DB parameters...")
|
|
||||||
print("\n")
|
if not os.path.exists('config'):
|
||||||
mastodon_db = input("Mastodon db name: ")
|
os.makedirs('config')
|
||||||
mastodon_db_user = input("Mastodon db user: ")
|
|
||||||
mailing_db = input("Mailing db name: ")
|
print("Setting up mailing DB parameters...")
|
||||||
mailing_db_user = input("Mailing db user: ")
|
print("\n")
|
||||||
mailing_db_table = input("Mailing db table: ")
|
mastodon_db = input("Mastodon db name: ")
|
||||||
with open(file_path, "w") as text_file:
|
mastodon_db_user = input("Mastodon db user: ")
|
||||||
print("mastodon_db: {}".format(mastodon_db), file=text_file)
|
mailing_db = input("Mailing db name: ")
|
||||||
print("mastodon_db_user: {}".format(mastodon_db_user), file=text_file)
|
mailing_db_user = input("Mailing db user: ")
|
||||||
print("mailing_db: {}".format(mailing_db), file=text_file)
|
mailing_db_table = input("Mailing db table: ")
|
||||||
print("mailing_db_user: {}".format(mailing_db_user), file=text_file)
|
inactive_days = input("Inactive days: ")
|
||||||
print("mailing_db_table: {}".format(mailing_db_table), file=text_file)
|
|
||||||
|
with open(file_path, "w") as text_file:
|
||||||
|
print("mastodon_db: {}".format(mastodon_db), file=text_file)
|
||||||
|
print("mastodon_db_user: {}".format(mastodon_db_user), file=text_file)
|
||||||
|
print("mailing_db: {}".format(mailing_db), file=text_file)
|
||||||
|
print("mailing_db_user: {}".format(mailing_db_user), file=text_file)
|
||||||
|
print("mailing_db_table: {}".format(mailing_db_table), file=text_file)
|
||||||
|
print("inactive_days: {}".format(inactive_days), file=text_file)
|
||||||
|
|
||||||
|
def create_database():
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(dbname='postgres',
|
||||||
|
user=mailing_db_user, host='',
|
||||||
|
password='')
|
||||||
|
|
||||||
|
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
print("Creating database " + mailing_db + ". Please wait...")
|
||||||
|
cur.execute(sql.SQL("CREATE DATABASE {}").format(
|
||||||
|
sql.Identifier(mailing_db))
|
||||||
|
)
|
||||||
|
print("Database " + mailing_db + " created!")
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
# Load configuration from config file
|
||||||
|
os.remove("config/db_config.txt")
|
||||||
|
print("Exiting. Run setup again with right parameters")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
print("\n")
|
||||||
|
print("Mailing db parameters saved to config.txt!")
|
||||||
|
print("\n")
|
||||||
|
|
||||||
def create_table(db, db_user, table, sql):
|
def create_table(db, db_user, table, sql):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
conn = None
|
conn = None
|
||||||
conn = psycopg2.connect(database = db, user = db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = db, user = db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
print("Creating table.. "+table)
|
print("Creating table.. "+table)
|
||||||
# Create the table in PostgreSQL database
|
# Create the table in PostgreSQL database
|
||||||
|
@ -68,85 +136,25 @@ def create_table(db, db_user, table, sql):
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
#############################################################################################
|
# main
|
||||||
|
|
||||||
# Load configuration from config file
|
if __name__ == '__main__':
|
||||||
config_filepath = "config.txt"
|
|
||||||
mastodon_db = get_parameter("mastodon_db", config_filepath) # E.g., mastodon_production
|
|
||||||
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath) # E.g., mastodon
|
|
||||||
mailing_db = get_parameter("mailing_db", config_filepath) # E.g., inactive
|
|
||||||
mailing_db_user = get_parameter("mailing_db_user", config_filepath) # E.g., mastodon
|
|
||||||
mailing_db_table = get_parameter("mailing_db_table", config_filepath) # E.g., inactive_users
|
|
||||||
|
|
||||||
############################################################
|
mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table = get_config()
|
||||||
# create database
|
|
||||||
############################################################
|
|
||||||
|
|
||||||
try:
|
create_database()
|
||||||
|
|
||||||
conn = psycopg2.connect(dbname='postgres',
|
########################################
|
||||||
user=mailing_db_user, host='',
|
# create mailing DB table
|
||||||
password='')
|
|
||||||
|
|
||||||
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
|
db = mailing_db
|
||||||
|
db_user = mailing_db_user
|
||||||
|
table = mailing_db_table
|
||||||
|
sql = "create table " + table + "(datetime timestamptz, account_id bigint primary key, username varchar(30), email varchar(60), emailed_at timestamptz,"
|
||||||
|
sql += "emailed boolean default False, deleted boolean default False, elapsed_days varchar(30), to_be_deleted boolean default False,"
|
||||||
|
sql += "recipient_error boolean default False, feedback boolean default False, current_sign_in_at timestamptz)"
|
||||||
|
create_table(db, db_user, table, sql)
|
||||||
|
|
||||||
cur = conn.cursor()
|
#####################################
|
||||||
|
|
||||||
print("Creating database " + mailing_db + ". Please wait...")
|
print("Done!\nNow you can run setup.py!\n")
|
||||||
cur.execute(sql.SQL("CREATE DATABASE {}").format(
|
|
||||||
sql.Identifier(mailing_db))
|
|
||||||
)
|
|
||||||
print("Database " + mailing_db + " created!")
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
#############################################################################################
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = None
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
# Load configuration from config file
|
|
||||||
os.remove("config.txt")
|
|
||||||
print("Exiting. Run setup again with right parameters")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
print("\n")
|
|
||||||
print("Mailing db parameters saved to config.txt!")
|
|
||||||
print("\n")
|
|
||||||
|
|
||||||
############################################################
|
|
||||||
# Create needed tables
|
|
||||||
############################################################
|
|
||||||
|
|
||||||
print("Creating table...")
|
|
||||||
|
|
||||||
########################################
|
|
||||||
|
|
||||||
db = mailing_db
|
|
||||||
db_user = mailing_db_user
|
|
||||||
table = mailing_db_table
|
|
||||||
sql = "create table " + table + "(datetime timestamptz, account_id int primary key, username varchar(30), email varchar(50), emailed_at timestamptz,"
|
|
||||||
sql += "emailed boolean default False, deleted boolean default False, elapsed_days varchar(30), to_be_deleted boolean default False,"
|
|
||||||
sql += "recipient_error boolean default False, feedback boolean default False)"
|
|
||||||
create_table(db, db_user, table, sql)
|
|
||||||
|
|
||||||
#####################################
|
|
||||||
|
|
||||||
print("Done!")
|
|
||||||
print("Now you can run setup.py!")
|
|
||||||
print("\n")
|
|
||||||
|
|
|
@ -3,150 +3,173 @@
|
||||||
|
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
import time
|
import time
|
||||||
import threading
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
def delete_inactives(mailing_db, mailing_db_user, mailing_db_table, deletion_accepted, query, id_array, username_array):
|
def delete_inactives(deletion_accepted, query):
|
||||||
|
|
||||||
conn = None
|
id_array = []
|
||||||
|
|
||||||
try:
|
username_array = []
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
conn = None
|
||||||
|
|
||||||
cur = conn.cursor()
|
try:
|
||||||
|
|
||||||
cur.execute(query)
|
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
for row in cur:
|
cur = conn.cursor()
|
||||||
|
|
||||||
id_array.append(row[0])
|
cur.execute(query)
|
||||||
username_array.append(row[1])
|
|
||||||
|
|
||||||
i = 0
|
for row in cur:
|
||||||
if len(id_array) == 0:
|
|
||||||
if deletion_accepted == True:
|
|
||||||
print("None inactive users who accepted to be deleted found!")
|
|
||||||
elif deletion_accepted == False:
|
|
||||||
print("None inactive users to be deleted!")
|
|
||||||
return
|
|
||||||
|
|
||||||
while i < len(id_array):
|
id_array.append(row[0])
|
||||||
|
|
||||||
if deletion_accepted == True:
|
username_array.append(row[1])
|
||||||
print("Deleting inactive users who accepted to be deleted...")
|
|
||||||
elif deletion_accepted == False:
|
|
||||||
print("Deleting inactive users who do not reply our email...")
|
|
||||||
|
|
||||||
print("\n")
|
i = 0
|
||||||
print("Deleting user " + str(i) + " of " + str(len(id_array)) + " users")
|
|
||||||
print("Deleting user with id " + str(id_array[i]) + ", username: " + username_array[i])
|
|
||||||
os.system("RAILS_ENV=production " + rvm_ruby + " " + mastodon_full_path + "/bin/tootctl accounts delete " + username_array[i])
|
|
||||||
delete_user(id_array[i], username_array[i])
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
cur.close()
|
if len(id_array) == 0:
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
if deletion_accepted == True:
|
||||||
|
|
||||||
print(error)
|
print("None inactive users who accepted to be deleted found!")
|
||||||
|
|
||||||
finally:
|
elif deletion_accepted == False:
|
||||||
|
|
||||||
if conn is not None:
|
print("None inactive users to be deleted!")
|
||||||
|
|
||||||
conn.close()
|
return
|
||||||
|
|
||||||
###################################################################################
|
while i < len(id_array):
|
||||||
# update user as deleted
|
|
||||||
###################################################################################
|
if deletion_accepted == True:
|
||||||
|
|
||||||
|
print("Deleting inactive users who accepted to be deleted...")
|
||||||
|
|
||||||
|
elif deletion_accepted == False:
|
||||||
|
|
||||||
|
print("Deleting inactive users who do not reply our email...")
|
||||||
|
|
||||||
|
print(f"\nDeleting user {str(i)} of {str(len(id_array))} users")
|
||||||
|
|
||||||
|
print(f"Deleting user with id {str(id_array[i])}, username: {username_array[i]}")
|
||||||
|
|
||||||
|
os.system(f"RAILS_ENV=production {rvm_ruby} {mastodon_full_path}/bin/tootctl accounts delete {username_array[i]}")
|
||||||
|
|
||||||
|
delete_user(id_array[i], username_array[i])
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
def delete_user(id, username):
|
def delete_user(id, username):
|
||||||
|
|
||||||
conn = None
|
conn = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
cur.execute("DELETE FROM " + mailing_db_table + " where account_id=(%s)", (str(id),))
|
cur.execute("DELETE FROM " + mailing_db_table + " where account_id=(%s)", (str(id),))
|
||||||
print("Deleting user " + str(id) + ", username " + str(username))
|
|
||||||
|
|
||||||
conn.commit()
|
print(f"Deleting user {str(id)}, username {str(username)}")
|
||||||
|
|
||||||
cur.close()
|
conn.commit()
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
cur.close()
|
||||||
|
|
||||||
print(error)
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
finally:
|
print(error)
|
||||||
|
|
||||||
if conn is not None:
|
finally:
|
||||||
|
|
||||||
conn.close()
|
if conn is not None:
|
||||||
|
|
||||||
###############################################################################
|
conn.close()
|
||||||
# INITIALISATION
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# Returns the parameter from the specified file
|
|
||||||
def get_parameter( parameter, file_path ):
|
def get_parameter( parameter, file_path ):
|
||||||
|
|
||||||
# Check if secrets file exists
|
# Check if secrets file exists
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
|
|
||||||
if file_path == "secrets/secrets.txt":
|
if file_path == "secrets/secrets.txt":
|
||||||
print("File %s not found, exiting. Run setup.py."%file_path)
|
|
||||||
|
print("File %s not found, exiting. Run setup.py."%file_path)
|
||||||
|
|
||||||
elif file_path == "config.txt":
|
elif file_path == "config.txt":
|
||||||
print("File %s not found, exiting. Run db-setup.py."%file_path)
|
|
||||||
|
print("File %s not found, exiting. Run db-setup.py."%file_path)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Find parameter in file
|
# Find parameter in file
|
||||||
with open( file_path ) as f:
|
with open( file_path ) as f:
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
|
|
||||||
if line.startswith( parameter ):
|
if line.startswith( parameter ):
|
||||||
|
|
||||||
return line.replace(parameter + ":", "").strip()
|
return line.replace(parameter + ":", "").strip()
|
||||||
|
|
||||||
# Cannot find parameter, exit
|
# Cannot find parameter, exit
|
||||||
print(file_path + " Missing parameter %s "%parameter)
|
print(f"{file_path} Missing parameter {parameter}")
|
||||||
print("Run setup.py")
|
print("Run setup.py")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Load secrets from secrets file
|
def config():
|
||||||
secrets_filepath = "secrets/secrets.txt"
|
|
||||||
mastodon_full_path = get_parameter("mastodon_full_path", secrets_filepath)
|
|
||||||
|
|
||||||
# Load configuration from config file
|
secrets_filepath = "secrets/secrets.txt"
|
||||||
config_filepath = "config.txt"
|
mastodon_full_path = get_parameter("mastodon_full_path", secrets_filepath)
|
||||||
mailing_db = get_parameter("mailing_db", config_filepath)
|
|
||||||
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
# Load configuration from config file
|
||||||
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
config_filepath = "config.txt"
|
||||||
|
mailing_db = get_parameter("mailing_db", config_filepath)
|
||||||
|
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
||||||
|
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
||||||
|
|
||||||
|
return (mastodon_full_path, mailing_db, mailing_db_user, mailing_db_table)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# main
|
||||||
|
|
||||||
global rvm_ruby
|
if __name__ == '__main__':
|
||||||
rvm_ruby = os.environ['HOME'] + "/.rbenv/shims/ruby"
|
|
||||||
|
|
||||||
###############################################################################
|
mastodon_full_path, mailing_db, mailing_db_user, mailing_db_table = config()
|
||||||
# select users who replied the warning email saying yes to deletion
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
deletion_accepted = True
|
global rvm_ruby
|
||||||
query = "select account_id, username, email, to_be_deleted, feedback, recipient_error, elapsed_days from " + mailing_db_table + " where to_be_deleted = 't' and feedback = 't' and recipient_error = 'f' and emailed_at < now() - interval '31 days'"
|
rvm_ruby = os.environ['HOME'] + "/.rbenv/shims/ruby"
|
||||||
id_array = []
|
|
||||||
username_array = []
|
|
||||||
delete_inactives(mailing_db, mailing_db_user, mailing_db_table, deletion_accepted, query, id_array, username_array)
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# select users who don't replied to email after 30 days
|
# select and delete users who replied the warning email saying yes to deletion
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
deletion_accepted = False
|
deletion_accepted = True
|
||||||
query = "select account_id, username, email, to_be_deleted, feedback, recipient_error, elapsed_days from " + mailing_db_table + " where to_be_deleted = 'f' and feedback = 'f' and recipient_error = 'f' and emailed_at < now() - interval '31 days'"
|
|
||||||
id_array = []
|
query = "select account_id, username, email, to_be_deleted, feedback, recipient_error, elapsed_days from " + mailing_db_table + " where to_be_deleted and feedback"
|
||||||
username_array = []
|
|
||||||
delete_inactives(mailing_db, mailing_db_user, mailing_db_table, deletion_accepted, query, id_array, username_array)
|
delete_inactives(deletion_accepted, query)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# select and delete users who don't replied the email after 31 days
|
||||||
|
|
||||||
|
deletion_accepted = False
|
||||||
|
|
||||||
|
query = "select account_id, username, email, to_be_deleted, feedback, recipient_error, elapsed_days from " + mailing_db_table + " where not feedback and elapsed_days = '31'"
|
||||||
|
|
||||||
|
delete_inactives(deletion_accepted, query)
|
||||||
|
|
239
edit_status.py
239
edit_status.py
|
@ -8,123 +8,101 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
try:
|
||||||
##############################################################################
|
from prettytable import PrettyTable
|
||||||
# ask what user to be edit
|
except ModuleNotFoundError as mod_not_found:
|
||||||
##############################################################################
|
print(f"{mod_not_found}. Run 'pip install -r requirements.txt' and try again")
|
||||||
|
|
||||||
def ask_what_user():
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
useremail = input("Enter user email address: (press q to quit) ")
|
|
||||||
if useremail == 'q':
|
|
||||||
sys.exit()
|
|
||||||
else:
|
|
||||||
user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback = get_user(useremail)
|
|
||||||
return (user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback)
|
|
||||||
except:
|
|
||||||
|
|
||||||
if useremail != 'q':
|
|
||||||
print("Enter an existent email address!")
|
|
||||||
sys.exit("Good bye!")
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# get user row
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
def get_user(email):
|
def get_user(email):
|
||||||
|
|
||||||
try:
|
found_it = False
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
try:
|
||||||
|
|
||||||
cur = conn.cursor()
|
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
cur.execute("SELECT account_id, username, email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, feedback FROM " + mailing_db_table + " where email=(%s)", (email,))
|
cur = conn.cursor()
|
||||||
|
|
||||||
row = cur.fetchone()
|
cur.execute("SELECT account_id, username, email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, feedback FROM " + mailing_db_table + " where email=(%s)", (email,))
|
||||||
|
|
||||||
user_id = row[0]
|
row = cur.fetchone()
|
||||||
user_name = row[1]
|
|
||||||
user_email = row[2]
|
|
||||||
emailed_at = row[3].replace(tzinfo=None)
|
|
||||||
deleted = row[4]
|
|
||||||
elapsed_days = row[5]
|
|
||||||
to_be_deleted = row[6]
|
|
||||||
recipient_error = row[7]
|
|
||||||
user_feedback = row[8]
|
|
||||||
|
|
||||||
cur.close()
|
if row != None:
|
||||||
return (user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback)
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
found_it = True
|
||||||
|
|
||||||
print(error)
|
user_id = row[0]
|
||||||
|
user_name = row[1]
|
||||||
|
user_email = row[2]
|
||||||
|
emailed_at = row[3].replace(tzinfo=None)
|
||||||
|
deleted = row[4]
|
||||||
|
elapsed_days = row[5]
|
||||||
|
to_be_deleted = row[6]
|
||||||
|
recipient_error = row[7]
|
||||||
|
user_feedback = row[8]
|
||||||
|
|
||||||
finally:
|
else:
|
||||||
|
|
||||||
if conn is not None:
|
user_id = ''
|
||||||
|
user_name = ''
|
||||||
|
user_email = ''
|
||||||
|
emailed_at = ''
|
||||||
|
deleted = False
|
||||||
|
elapsed_days = '0'
|
||||||
|
to_be_deleted = False
|
||||||
|
recipient_error = False
|
||||||
|
user_feedback = False
|
||||||
|
|
||||||
conn.close()
|
cur.close()
|
||||||
|
|
||||||
###################################################################################
|
return (found_it, user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback)
|
||||||
# write to database mailing status of inactive users
|
|
||||||
###################################################################################
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
def update_user(will_be_deleted, recip_error, user_feedback, id):
|
def update_user(will_be_deleted, recip_error, user_feedback, id):
|
||||||
|
|
||||||
conn = None
|
conn = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
cur.execute("UPDATE " + mailing_db_table + " SET to_be_deleted=(%s), recipient_error=(%s), feedback=(%s) where account_id=(%s)", (will_be_deleted, recip_error, user_feedback, id))
|
cur.execute("UPDATE " + mailing_db_table + " SET to_be_deleted=(%s), recipient_error=(%s), feedback=(%s) where account_id=(%s)", (will_be_deleted, recip_error, user_feedback, id))
|
||||||
print("\n")
|
|
||||||
print("Updating user " + str(id))
|
|
||||||
|
|
||||||
conn.commit()
|
print(f"\nUpdating user {str(id)}")
|
||||||
|
|
||||||
cur.close()
|
conn.commit()
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
cur.close()
|
||||||
|
|
||||||
print(error)
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
finally:
|
print(error)
|
||||||
|
|
||||||
if conn is not None:
|
finally:
|
||||||
|
|
||||||
conn.close()
|
if conn is not None:
|
||||||
|
|
||||||
##################################################################################
|
conn.close()
|
||||||
# print user data
|
|
||||||
##################################################################################
|
|
||||||
|
|
||||||
def print_user(user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback):
|
|
||||||
|
|
||||||
print("\n")
|
|
||||||
print("--------------------------------------------------------------------------------------------------------------------------------")
|
|
||||||
print("| account_id: " + str(user_id) + " | username: " + str(user_name) + " | email: " + str(user_email) + " | emailed at: " + str(emailed_at) + " |")
|
|
||||||
print("| deleted: " + str(deleted) + " | elapsed days: " + str(elapsed_days) + " | to be deleted: " + str(to_be_deleted) + " | recipient error: " + str(recipient_error) + " | user feedback: " +str(user_feedback) + " |")
|
|
||||||
print("--------------------------------------------------------------------------------------------------------------------------------")
|
|
||||||
print("\n")
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# INITIALISATION
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# Returns the parameter from the specified file
|
|
||||||
def get_parameter( parameter, file_path ):
|
def get_parameter( parameter, file_path ):
|
||||||
|
|
||||||
# Check if secrets file exists
|
# Check if secrets file exists
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
if file_path == "secrets/secrets.txt":
|
if file_path == "secrets/secrets.txt":
|
||||||
print("File %s not found, exiting. Run setup.py."%file_path)
|
print(f"File {file_path} not found, exiting. Run setup.py.")
|
||||||
elif file_path == "config.txt":
|
elif file_path == "config.txt":
|
||||||
print("File %s not found, exiting. Run db-setup.py."%file_path)
|
print(f"File {file_path} not found, exiting. Run db-setup.py.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Find parameter in file
|
# Find parameter in file
|
||||||
|
@ -134,44 +112,81 @@ def get_parameter( parameter, file_path ):
|
||||||
return line.replace(parameter + ":", "").strip()
|
return line.replace(parameter + ":", "").strip()
|
||||||
|
|
||||||
# Cannot find parameter, exit
|
# Cannot find parameter, exit
|
||||||
print(file_path + " Missing parameter %s "%parameter)
|
print(f"{file_path} Missing parameter {parameter}\nRun setup.py")
|
||||||
print("Run setup.py")
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Load configuration from config file
|
def db_config():
|
||||||
config_filepath = "config.txt"
|
|
||||||
mastodon_db = get_parameter("mastodon_db", config_filepath)
|
|
||||||
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath)
|
|
||||||
mailing_db = get_parameter("mailing_db", config_filepath)
|
|
||||||
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
|
||||||
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
|
||||||
|
|
||||||
###############################################################################
|
# Load configuration from config file
|
||||||
|
config_filepath = "config.txt"
|
||||||
|
mastodon_db = get_parameter("mastodon_db", config_filepath)
|
||||||
|
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath)
|
||||||
|
mailing_db = get_parameter("mailing_db", config_filepath)
|
||||||
|
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
||||||
|
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
||||||
|
|
||||||
while True:
|
return (mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table)
|
||||||
|
|
||||||
user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback = ask_what_user()
|
# main
|
||||||
|
|
||||||
print_user(user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback)
|
if __name__ == '__main__':
|
||||||
|
|
||||||
willdeleteit = input("Do you want to mark user to be deleted? (press t for True or f for False) ")
|
mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table = db_config()
|
||||||
if willdeleteit == 'f':
|
|
||||||
willdeleteit = 'False'
|
|
||||||
elif willdeleteit == 't':
|
|
||||||
willdeleteit = 'True'
|
|
||||||
|
|
||||||
recip_error = input("Was the email refused? (press t for True or f for False) ")
|
while True:
|
||||||
if recip_error == 'f':
|
|
||||||
recip_error = 'False'
|
useremail = input("Enter user email address: (press q to quit) ")
|
||||||
elif recip_error == 't':
|
|
||||||
recip_error = 'True'
|
if useremail == 'q':
|
||||||
|
|
||||||
|
sys.exit('Bye.')
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
found_it, user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback = get_user(useremail)
|
||||||
|
|
||||||
|
if found_it:
|
||||||
|
|
||||||
|
print_table = PrettyTable()
|
||||||
|
|
||||||
|
print_table.field_names = ['id', 'username', 'email', 'emailed_at', 'deleted', 'elapsed_days', 'to_be_deleted', 'recipient_error', 'user_feedback']
|
||||||
|
|
||||||
|
print_table.add_row([user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback])
|
||||||
|
|
||||||
|
print(f'\n{print_table}\n')
|
||||||
|
|
||||||
|
willdeleteit = input("Do you want to mark user to be deleted? (press t for True or f for False) ")
|
||||||
|
if willdeleteit == 'f':
|
||||||
|
willdeleteit = 'False'
|
||||||
|
elif willdeleteit == 't':
|
||||||
|
willdeleteit = 'True'
|
||||||
|
|
||||||
|
recip_error = input("Was the email refused? (press t for True or f for False) ")
|
||||||
|
if recip_error == 'f':
|
||||||
|
recip_error = 'False'
|
||||||
|
elif recip_error == 't':
|
||||||
|
recip_error = 'True'
|
||||||
|
|
||||||
|
user_feed = input("Have the user replied? (press t for True or f for False) ")
|
||||||
|
if user_feed == 'f':
|
||||||
|
user_feed = 'False'
|
||||||
|
elif user_feed == 't':
|
||||||
|
user_feed = 'True'
|
||||||
|
|
||||||
|
update_user(willdeleteit, recip_error, user_feed, user_id)
|
||||||
|
|
||||||
|
found_it, user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback = get_user(useremail)
|
||||||
|
|
||||||
|
print_table = PrettyTable()
|
||||||
|
|
||||||
|
print_table.field_names = ['id', 'username', 'email', 'emailed_at', 'deleted', 'elapsed_days', 'to_be_deleted', 'recipient_error', 'user_feedback']
|
||||||
|
|
||||||
|
print_table.add_row([user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback])
|
||||||
|
|
||||||
|
print(f'\n{print_table}\n')
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
print(f'email {useremail} not found!')
|
||||||
|
|
||||||
user_feed = input("Have the user replied? (press t for True or f for False) ")
|
|
||||||
if user_feed == 'f':
|
|
||||||
user_feed = 'False'
|
|
||||||
elif user_feed == 't':
|
|
||||||
user_feed = 'True'
|
|
||||||
|
|
||||||
update_user(willdeleteit, recip_error, user_feed, user_id)
|
|
||||||
user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback = get_user(user_email)
|
|
||||||
print_user(user_id, user_name, user_email, emailed_at, deleted, elapsed_days, to_be_deleted, recipient_error, user_feedback)
|
|
||||||
|
|
468
inactives.py
Normal file
468
inactives.py
Normal file
|
@ -0,0 +1,468 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
import time
|
||||||
|
try:
|
||||||
|
import psycopg2
|
||||||
|
except ModuleNotFoundError as mod_not_found:
|
||||||
|
print(f"{mod_not_found}'. Run 'pip install -r requirements.txt' and try again")
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
import smtplib
|
||||||
|
from smtplib import SMTPException, SMTPAuthenticationError, SMTPConnectError, SMTPRecipientsRefused
|
||||||
|
import socket
|
||||||
|
from socket import gaierror
|
||||||
|
|
||||||
|
def smtp_config():
|
||||||
|
|
||||||
|
secrets_filepath = "secrets/secrets.txt"
|
||||||
|
smtp_host = get_parameter("smtp_host", secrets_filepath)
|
||||||
|
smtp_user_login = get_parameter("smtp_user_login", secrets_filepath)
|
||||||
|
smtp_user_password = get_parameter("smtp_user_password", secrets_filepath)
|
||||||
|
email_subject = get_parameter("email_subject", secrets_filepath)
|
||||||
|
|
||||||
|
return (smtp_host, smtp_user_login, smtp_user_password, email_subject)
|
||||||
|
|
||||||
|
def db_config():
|
||||||
|
|
||||||
|
config_filepath = "config/db_config.txt"
|
||||||
|
mastodon_db = get_parameter("mastodon_db", config_filepath)
|
||||||
|
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath)
|
||||||
|
mailing_db = get_parameter("mailing_db", config_filepath)
|
||||||
|
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
||||||
|
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
||||||
|
inactive_days = get_parameter("inactive_days", config_filepath)
|
||||||
|
|
||||||
|
return (mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table, inactive_days)
|
||||||
|
|
||||||
|
def get_parameter( parameter, file_path ):
|
||||||
|
|
||||||
|
# Check if secrets file exists
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
if file_path == "secrets/secrets.txt":
|
||||||
|
print("File %s not found, exiting. Run setup.py."%file_path)
|
||||||
|
elif file_path == "config/db_config.txt":
|
||||||
|
print("File %s not found, exiting. Run db-setup.py."%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)
|
||||||
|
print("Run setup.py")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
class Inactives:
|
||||||
|
|
||||||
|
name = "Inactives"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
smtp_host, smtp_user_login, smtp_user_password, email_subject = smtp_config()
|
||||||
|
|
||||||
|
mastodon_db, mastodon_db_user, mailing_db, mailing_db_user, mailing_db_table, inactive_days = db_config()
|
||||||
|
|
||||||
|
self.smtp_host = smtp_host
|
||||||
|
self.smtp_user_login = smtp_user_login
|
||||||
|
self.smtp_user_password = smtp_user_password
|
||||||
|
self.email_subject = email_subject
|
||||||
|
self.mastodon_db = mastodon_db
|
||||||
|
self.mastodon_db_user = mastodon_db_user
|
||||||
|
self.mailing_db = mailing_db
|
||||||
|
self.mailing_db_user = mailing_db_user
|
||||||
|
self.mailing_db_table = mailing_db_table
|
||||||
|
self.inactive_days = inactive_days
|
||||||
|
self.now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
def id(self):
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# get id of inactive users from inactive database
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mailing_db, user = self.mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT account_id FROM " + self.mailing_db_table)
|
||||||
|
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
if rows != []:
|
||||||
|
|
||||||
|
inactive_users_id = []
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
|
||||||
|
inactive_users_id.append(row[0])
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
inactive_users_id = []
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
return inactive_users_id
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def delete(self,ids_lst):
|
||||||
|
|
||||||
|
print(f'\nChecking {len(ids_lst)} ids to delete reactivated or deleted accounts...')
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while i < len(ids_lst):
|
||||||
|
|
||||||
|
seen = self.check_alive(self, ids_lst[i])
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mailing_db, user = self.mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT emailed_at FROM " + self.mailing_db_table + " where account_id=(%s)", (ids_lst[i],))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
email_datetime = row[0]
|
||||||
|
|
||||||
|
email_datetime = email_datetime.replace(tzinfo=None)
|
||||||
|
|
||||||
|
if seen != None:
|
||||||
|
|
||||||
|
reactivated = email_datetime < seen
|
||||||
|
|
||||||
|
last_year = datetime.today() - timedelta(days=int(self.inactive_days))
|
||||||
|
|
||||||
|
if reactivated == True or seen == None or seen > last_year: #if inactive user had reactivated its account or had deleted it we must delete related row from 'mailing_db_table'
|
||||||
|
|
||||||
|
cur.execute("DELETE FROM " + self.mailing_db_table + " where account_id=(%s)", (ids_lst[i],))
|
||||||
|
|
||||||
|
print(f"Deleting user {ids_lst[i]}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def get_inactives(self):
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Connect to Mastodon's Postgres DB to get last six months inactive users
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mastodon_db, user = self.mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("select account_id, email, current_sign_in_at from users where current_sign_in_at < now() - interval '" + self.inactive_days + " days' and disabled=False and approved=True order by current_sign_in_at desc")
|
||||||
|
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
inactive_account_id = []
|
||||||
|
|
||||||
|
inactive_email = []
|
||||||
|
|
||||||
|
current_sign_in_at = []
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
|
||||||
|
inactive_account_id.append(row[0])
|
||||||
|
|
||||||
|
inactive_email.append(row[1])
|
||||||
|
|
||||||
|
current_sign_in_at.append(row[2])
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
print(f'inactive accounts found: {len(inactive_account_id)}')
|
||||||
|
|
||||||
|
return (inactive_account_id, inactive_email, current_sign_in_at)
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def usernames(self, account_ids):
|
||||||
|
|
||||||
|
########################################################################################################
|
||||||
|
# get accounts usernames #
|
||||||
|
########################################################################################################
|
||||||
|
|
||||||
|
inactive_usernames = []
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(account_ids):
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mastodon_db, user = self.mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
inactive_id = account_ids[i]
|
||||||
|
|
||||||
|
cur.execute("select username from accounts where id = '%s';", [inactive_id])
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
new_username = row[0]
|
||||||
|
|
||||||
|
inactive_usernames.append(new_username)
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return inactive_usernames
|
||||||
|
|
||||||
|
def mailing(self, account_ids, account_emails, account_usernames, account_current_sign_in_ats):
|
||||||
|
|
||||||
|
###########################################################################################################
|
||||||
|
# email inactive users
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
fp = open('message.txt')
|
||||||
|
text = fp.read()
|
||||||
|
message = MIMEText(text)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
except:
|
||||||
|
|
||||||
|
print("message.txt file not found! Create it and write in the message you want for your inactive users.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(account_emails):
|
||||||
|
|
||||||
|
been_emailed = self.email_sent(self, account_ids[i])
|
||||||
|
|
||||||
|
if been_emailed == False:
|
||||||
|
|
||||||
|
# Create message object instance
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
|
||||||
|
# Declare message elements
|
||||||
|
msg['From'] = self.smtp_user_login
|
||||||
|
msg['To'] = account_emails[i]
|
||||||
|
msg['Subject'] = account_usernames[i] + " " + self.email_subject
|
||||||
|
|
||||||
|
# Add the message body to the object instance
|
||||||
|
msg.attach(message)
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Create the server connection
|
||||||
|
server = smtplib.SMTP(self.smtp_host)
|
||||||
|
# Switch the connection over to TLS encryption
|
||||||
|
server.starttls()
|
||||||
|
# Authenticate with the server
|
||||||
|
server.login(self.smtp_user_login, self.smtp_user_password)
|
||||||
|
# Send the message
|
||||||
|
server.sendmail(msg['From'], msg['To'], msg.as_string())
|
||||||
|
# Disconnect
|
||||||
|
server.quit()
|
||||||
|
|
||||||
|
print("Successfully sent email message to %s" % msg['To'])
|
||||||
|
emailed = True
|
||||||
|
|
||||||
|
self.write_db(self, self.now, account_ids[i], account_usernames[i], account_emails[i], self.now, emailed, account_current_sign_in_ats[i])
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
except SMTPAuthenticationError as auth_error:
|
||||||
|
|
||||||
|
print(auth_error)
|
||||||
|
sys.exit(":-(")
|
||||||
|
|
||||||
|
except socket.gaierror as socket_error:
|
||||||
|
|
||||||
|
print(socket_error)
|
||||||
|
print("Unknown SMTP server")
|
||||||
|
sys.exit(":-(")
|
||||||
|
|
||||||
|
except SMTPRecipientsRefused as recip_error:
|
||||||
|
|
||||||
|
print(recip_error)
|
||||||
|
emailed = False
|
||||||
|
self.write_db(self, self.now, account_ids[i], account_usernames[i], account_emails[i], self.now, emailed, account_current_sign_in_ats[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
emailed = True
|
||||||
|
self.write_db(self, self.now, account_ids[i], account_usernames[i], account_emails[i], self.now, emailed, account_current_sign_in_ats[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def write_db(self, now, id, username, email, emailed_at, emailed, current_sign_in_at):
|
||||||
|
|
||||||
|
###################################################################################
|
||||||
|
# write to mailing database the status of inactive users
|
||||||
|
|
||||||
|
|
||||||
|
insert_line = "INSERT INTO " + self.mailing_db_table + "(datetime, account_id, username, email, emailed_at, emailed, current_sign_in_at) VALUES(%s,%s,%s,%s,%s,%s,%s) ON CONFLICT DO NOTHING"
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mailing_db, user = self.mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT account_id FROM " + self.mailing_db_table + " where account_id=(%s)", (id,))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
if row == None:
|
||||||
|
|
||||||
|
cur.execute(insert_line, (now, id, username, email, now, emailed, current_sign_in_at))
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
if emailed == True:
|
||||||
|
|
||||||
|
cur.execute("SELECT datetime FROM " + self.mailing_db_table + " where account_id=(%s)", (id,))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
delta = now-row[0]
|
||||||
|
|
||||||
|
cur.execute("UPDATE " + self.mailing_db_table + " SET elapsed_days=(%s), email=(%s), emailed=(%s), current_sign_in_at=(%s) where account_id=(%s)", (delta.days, email, emailed, current_sign_in_at, id))
|
||||||
|
|
||||||
|
print(f"Updating user {str(id)}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def email_sent(self, account_id):
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# check if inactive user had been already emailed
|
||||||
|
|
||||||
|
been_emailed = False
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mailing_db, user = self.mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("SELECT emailed FROM " + self.mailing_db_table + " where account_id=(%s)", (account_id,))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
if row != None:
|
||||||
|
|
||||||
|
been_emailed = row[0]
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
return been_emailed
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
if conn is not None:
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_alive(self, id):
|
||||||
|
|
||||||
|
conn = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database = self.mastodon_db, user = self.mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
cur.execute("select current_sign_in_at from users where account_id=(%s)", (id,))
|
||||||
|
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
if row != None:
|
||||||
|
|
||||||
|
seen = row[0]
|
||||||
|
else:
|
||||||
|
|
||||||
|
seen = None
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
return seen
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
|
||||||
|
print(error)
|
393
mailing.py
393
mailing.py
|
@ -1,396 +1,21 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from datetime import datetime, timezone, timedelta
|
from inactives import Inactives
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import os.path
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
import smtplib
|
|
||||||
from smtplib import SMTPException, SMTPAuthenticationError, SMTPConnectError, SMTPRecipientsRefused
|
|
||||||
import psycopg2
|
|
||||||
import socket
|
|
||||||
from socket import gaierror
|
|
||||||
|
|
||||||
###################################################################################
|
# main
|
||||||
# write to database mailing status of inactive users
|
|
||||||
###################################################################################
|
|
||||||
|
|
||||||
def write_db(now, id, username, email, emailed_at, emailed):
|
if __name__ == '__main__':
|
||||||
|
|
||||||
insert_line = "INSERT INTO " + mailing_db_table + "(datetime, account_id, username, email, emailed_at, emailed) VALUES(%s,%s,%s,%s,%s,%s) ON CONFLICT DO NOTHING"
|
inactives = Inactives()
|
||||||
|
|
||||||
conn = None
|
inactives_ids = inactives.id()
|
||||||
|
|
||||||
try:
|
inactives.delete(inactives_ids)
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
account_ids, account_emails, account_last_sign_in_ats = inactives.get_inactives()
|
||||||
|
|
||||||
cur = conn.cursor()
|
account_usernames = inactives.usernames(account_ids)
|
||||||
|
|
||||||
cur.execute("SELECT account_id FROM " + mailing_db_table + " where account_id=(%s)", (id,))
|
inactives.mailing(account_ids, account_emails, account_usernames, account_last_sign_in_ats)
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
|
|
||||||
if row == None:
|
|
||||||
|
|
||||||
cur.execute(insert_line, (now, id, username, email, now, emailed))
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
if emailed == True:
|
|
||||||
|
|
||||||
cur.execute("SELECT datetime FROM " + mailing_db_table + " where account_id=(%s)", (id,))
|
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
delta = now-row[0]
|
|
||||||
|
|
||||||
cur.execute("UPDATE " + mailing_db_table + " SET elapsed_days=(%s), email=(%s), emailed=(%s) where account_id=(%s)", (delta, email, emailed, id))
|
|
||||||
print("Updating user " + str(id))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# check if inactive user had been already emailed
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
def email_sent(id):
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT emailed FROM " + mailing_db_table + " where account_id=(%s)", (id,))
|
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
|
|
||||||
if row == None:
|
|
||||||
|
|
||||||
been_emailed = False
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
been_emailed = row[0]
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return been_emailed
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Connect to Mastodon's Postgres DB to check if any inactive user is back online
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
def check_alive(id):
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mastodon_db, user = mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("select last_sign_in_at from users where account_id=(%s)", (id,))
|
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
|
|
||||||
if row != None:
|
|
||||||
seen = row[0]
|
|
||||||
else:
|
|
||||||
seen = None
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
return seen
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# INITIALISATION
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# Returns the parameter from the specified file
|
|
||||||
def get_parameter( parameter, file_path ):
|
|
||||||
# Check if secrets file exists
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
if file_path == "secrets/secrets.txt":
|
|
||||||
print("File %s not found, exiting. Run setup.py."%file_path)
|
|
||||||
elif file_path == "config.txt":
|
|
||||||
print("File %s not found, exiting. Run db-setup.py."%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)
|
|
||||||
print("Run setup.py")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# Load secrets from secrets file
|
|
||||||
secrets_filepath = "secrets/secrets.txt"
|
|
||||||
smtp_host = get_parameter("smtp_host", secrets_filepath)
|
|
||||||
smtp_user_login = get_parameter("smtp_user_login", secrets_filepath)
|
|
||||||
smtp_user_password = get_parameter("smtp_user_password", secrets_filepath)
|
|
||||||
email_subject = get_parameter("email_subject", secrets_filepath)
|
|
||||||
|
|
||||||
# Load configuration from config file
|
|
||||||
config_filepath = "config.txt"
|
|
||||||
mastodon_db = get_parameter("mastodon_db", config_filepath)
|
|
||||||
mastodon_db_user = get_parameter("mastodon_db_user", config_filepath)
|
|
||||||
mailing_db = get_parameter("mailing_db", config_filepath)
|
|
||||||
mailing_db_user = get_parameter("mailing_db_user", config_filepath)
|
|
||||||
mailing_db_table = get_parameter("mailing_db_table", config_filepath)
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# check if inactive user is back online
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT account_id FROM " + mailing_db_table)
|
|
||||||
|
|
||||||
rows = cur.fetchall()
|
|
||||||
if rows != []:
|
|
||||||
|
|
||||||
inactive_users_id = []
|
|
||||||
|
|
||||||
for row in rows:
|
|
||||||
|
|
||||||
inactive_users_id.append(row[0])
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
inactive_users_id = []
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(inactive_users_id):
|
|
||||||
|
|
||||||
seen = check_alive(inactive_users_id[i])
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mailing_db, user = mailing_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("SELECT emailed_at FROM " + mailing_db_table + " where account_id=(%s)", (inactive_users_id[i],))
|
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
email_datetime = row[0]
|
|
||||||
email_datetime = email_datetime.replace(tzinfo=None)
|
|
||||||
|
|
||||||
if seen != None:
|
|
||||||
|
|
||||||
reactivated = email_datetime < seen
|
|
||||||
last_year = datetime.today() - timedelta(days=365)
|
|
||||||
|
|
||||||
if reactivated == True or seen == None or seen > last_year: #if inactive user had reactivated its account or had deleted it we must delete related row from 'mailing_db_table'
|
|
||||||
|
|
||||||
cur.execute("DELETE FROM " + mailing_db_table + " where account_id=(%s)", (inactive_users_id[i],))
|
|
||||||
print("Deleting user " + str(inactive_users_id[i]))
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Connect to Mastodon's Postgres DB to get last year inactive users
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mastodon_db, user = mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute("select account_id, email from users where last_sign_in_at < now() - interval '365 days' and disabled=False and approved=True order by last_sign_in_at desc;")
|
|
||||||
rows = cur.fetchall()
|
|
||||||
|
|
||||||
inactive_account_id = []
|
|
||||||
inactive_email = []
|
|
||||||
|
|
||||||
for row in rows:
|
|
||||||
inactive_account_id.append(row[0])
|
|
||||||
inactive_email.append(row[1])
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
########################################################################################################
|
|
||||||
# get related usernames #
|
|
||||||
########################################################################################################
|
|
||||||
|
|
||||||
inactive_usernames = []
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(inactive_account_id):
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
conn = psycopg2.connect(database = mastodon_db, user = mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432")
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
inactive_id = inactive_account_id[i]
|
|
||||||
cur.execute("select username from accounts where id = '%s';", [inactive_id])
|
|
||||||
|
|
||||||
row = cur.fetchone()
|
|
||||||
new_username = row[0]
|
|
||||||
inactive_usernames.append(new_username)
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
|
||||||
|
|
||||||
print(error)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
if conn is not None:
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
###########################################################################################################
|
|
||||||
# email inactive users
|
|
||||||
###########################################################################################################
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
fp = open('message.txt')
|
|
||||||
text = fp.read()
|
|
||||||
message = MIMEText(text)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
except:
|
|
||||||
|
|
||||||
print("message.txt file not found! Create it and write in the message you want for your inactive users.")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(inactive_email):
|
|
||||||
|
|
||||||
been_emailed = email_sent(inactive_account_id[i])
|
|
||||||
|
|
||||||
if been_emailed == False:
|
|
||||||
|
|
||||||
# Create message object instance
|
|
||||||
msg = MIMEMultipart()
|
|
||||||
|
|
||||||
# Declare message elements
|
|
||||||
msg['From'] = smtp_user_login
|
|
||||||
msg['To'] = inactive_email[i]
|
|
||||||
msg['Subject'] = inactive_usernames[i] + " " + email_subject
|
|
||||||
|
|
||||||
# Add the message body to the object instance
|
|
||||||
msg.attach(message)
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
# Create the server connection
|
|
||||||
server = smtplib.SMTP(smtp_host)
|
|
||||||
# Switch the connection over to TLS encryption
|
|
||||||
server.starttls()
|
|
||||||
# Authenticate with the server
|
|
||||||
server.login(smtp_user_login, smtp_user_password)
|
|
||||||
# Send the message
|
|
||||||
server.sendmail(msg['From'], msg['To'], msg.as_string())
|
|
||||||
# Disconnect
|
|
||||||
server.quit()
|
|
||||||
|
|
||||||
print("Successfully sent email message to %s" % msg['To'])
|
|
||||||
emailed = True
|
|
||||||
write_db(now, inactive_account_id[i], inactive_usernames[i], inactive_email[i], now, emailed)
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
except SMTPAuthenticationError as auth_error:
|
|
||||||
|
|
||||||
print(auth_error)
|
|
||||||
sys.exit(":-(")
|
|
||||||
|
|
||||||
except socket.gaierror as socket_error:
|
|
||||||
|
|
||||||
print(socket_error)
|
|
||||||
print("Unknown SMTP server")
|
|
||||||
sys.exit(":-(")
|
|
||||||
|
|
||||||
except SMTPRecipientsRefused as recip_error:
|
|
||||||
|
|
||||||
print(recip_error)
|
|
||||||
emailed = False
|
|
||||||
write_db(now, inactive_account_id[i], inactive_usernames[i], inactive_email[i], now, emailed)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
emailed = True
|
|
||||||
write_db(now, inactive_account_id[i], inactive_usernames[i], inactive_email[i], now, emailed)
|
|
||||||
i += 1
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
psycopg2-binary>=2.8.4
|
psycopg2-binary
|
||||||
|
prettytable
|
||||||
|
|
Loading…
Referencia en una nova incidència