first commit

This commit is contained in:
salvadorpla 2019-11-30 14:07:16 +01:00
commit 688496d857
S'han modificat 4 arxius amb 604 adicions i 0 eliminacions

1
README.md Normal file
Veure arxiu

@ -0,0 +1 @@
# mailing

152
db-setup.py Normal file
Veure arxiu

@ -0,0 +1,152 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pdb
import getpass
import os
import sys
import psycopg2
from psycopg2 import sql
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
# 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):
print("File %s not found, asking."%file_path)
write_parameter( parameter, 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)
def write_parameter( parameter, file_path ):
print("Setting up mailing DB parameters...")
print("\n")
mastodon_db = input("Mastodon db name: ")
mastodon_db_user = input("Mastodon db user: ")
mailing_db = input("Mailing db name: ")
mailing_db_user = input("Mailing db user: ")
mailing_db_table = input("Mailing db table: ")
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)
def create_table(db, db_user, table, sql):
try:
conn = None
conn = psycopg2.connect(database = db, user = db_user, password = "", host = "/var/run/postgresql", port = "5432")
cur = conn.cursor()
print("Creating table.. "+table)
# Create the table in PostgreSQL database
cur.execute(sql)
conn.commit()
print("Table "+table+" created!")
print("\n")
except (Exception, psycopg2.DatabaseError) as error:
print(error)
finally:
if conn is not None:
conn.close()
#############################################################################################
# Load configuration from config file
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
############################################################
# 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.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, emailed boolean default False, deleted boolean default False, elapse_days varchar(30))"
create_table(db, db_user, table, sql)
#####################################
print("Done!")
print("Now you can run setup.py!")
print("\n")

390
mailing.py Normal file
Veure arxiu

@ -0,0 +1,390 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import datetime, timezone
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
###################################################################################
# write to database mailing status of inactive users
###################################################################################
def write_db(now, id, username, email, emailed_at, emailed):
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"
conn = None
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 + " where account_id=(%s)", (id,))
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))
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()
seen = row[0]
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 email_datetime < seen:
cur.execute("DELETE FROM " + mailing_db_table + " where account_id=(%s)", (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)
print(type(message))
print(message)
except:
print("message.txt file not found! Create it and write in the message you want for your inactive users.")
finally:
fp.close()
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'] = 'notificacions@mastodont.cat'
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

61
setup.py Normal file
Veure arxiu

@ -0,0 +1,61 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pdb
import getpass
import fileinput,re
import os
import sys
def create_dir():
if not os.path.exists('secrets'):
os.makedirs('secrets')
def create_file():
if not os.path.exists('secrets/secrets.txt'):
with open('secrets/secrets.txt', 'w'): pass
print(secrets_filepath + " created!")
def write_parameter( parameter, file_path ):
print("\n")
print("Setting up SMTP parameters...")
smtp_host = input("Enter SMTP hostname: ")
smtp_user_login = input("Enter SMTP user login, ex. user@" + smtp_host +"? ")
smtp_user_password = getpass.getpass("SMTP user password? ")
email_subject = input("Enter the subject of the email: ")
with open(file_path, "w") as text_file:
print("smtp_host: {}".format(smtp_host), file=text_file)
print("smtp_user_login: {}".format(smtp_user_login), file=text_file)
print("smtp_user_password: {}".format(smtp_user_password), file=text_file)
print("email_subject: {}".format(email_subject), file=text_file)
# 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):
print("File %s not found, creating it."%file_path)
create_dir()
create_file()
write_parameter( parameter, file_path )
print("\n")
print("SMTP setup done!\n")
print("Now you can run mailing.py!")
# 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)
# 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_pass = get_parameter("smtp_user_pass", secrets_filepath)
email_subject = get_parameter("email_subject", secrets_filepath)