2019-11-30 14:07:16 +01:00
#!/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
2019-11-30 14:44:23 +01:00
msg [ ' From ' ] = smtp_user_login
2019-11-30 14:07:16 +01:00
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