Skip to content

Commit

Permalink
Added pylint suggestions, docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
Niepawowsky committed Feb 1, 2024
1 parent 91a6b20 commit 2845484
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 107 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# auto_mail_sender
App for sending e-mail with remiders about books return deadlines

Create .env file in main directory. Copy and paste below template:
FIRST_NAME='your name
LAST_NAME='your last name'
EMAIL='your mail'
PASSWORD='password to your mail'
SMTP_SERVER='smtp server name'
PORT='port to your server'
18 changes: 7 additions & 11 deletions database/db_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def create_database(self):
author TEXT NOT NULL,
return_at DATE)'''
)
def _execute_query(self, query, params):
def execute_query(self, query, params):

with DbManager(connection=self.connection) as database:
cursor = database.cursor
Expand Down Expand Up @@ -81,7 +81,7 @@ def get_borrowed_books_by_today(self):
FROM borrowed_books
WHERE return_at > ?'''

result = self._execute_query(query, (today,))
result = self.execute_query(query, (today,))

for name, email, title, return_at in result:
return_date = datetime.strptime(return_at, '%Y-%m-%d %H:%M:%S')
Expand All @@ -90,7 +90,7 @@ def get_borrowed_books_by_today(self):

return borrower_list

def get_borrowed_history(self):
def get_borrowed_passed(self):
"""
The get_borrowed_for_remider function returns a list of
namedtuples containing the name, email, title and return_at
Expand All @@ -100,26 +100,22 @@ def get_borrowed_history(self):
:param self: Represent the instance of the class
:return: A list of named tuples
"""
# today = datetime.today()
today = datetime.today()
borrower = namedtuple('Borrower', 'name email title return_at')
borrower_list = []
query = '''SELECT
name,
email,
title,
return_at
FROM borrowed_books'''
FROM borrowed_books
WHERE return_at < ?'''

result = self._execute_query(query, None)
result = self.execute_query(query, (today,))

for name, email, title, return_at in result:
return_date = datetime.strptime(return_at, '%Y-%m-%d %H:%M:%S')
return_date.strftime('%Y-%m-%d')
borrower_list.append(borrower(name, email, title, return_date))

return borrower_list


def add_record(self):
pass

125 changes: 96 additions & 29 deletions mail_sender.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
import datetime
import smtplib, ssl
from dotenv import load_dotenv
from os import environ, getenv
from string import Template
'''
Module that gathers objects from template_render.py and db_service.py.
Main logic is placed here. Proper message is sent to selected persons from database
'''

import smtplib
import ssl
from os import getenv
from dotenv import load_dotenv
from templates.template_render import EmailTemplates
from database.db_service import DataBaseService


class MailSender():
'''
It's a class that creates proper mail message to proper user, that have borrowed a book.
It collects info from db_service and template_render and combines it togheter
'''

@staticmethod
def send_data(func):

"""
The send_data function is a decorator that adds the
following keyword arguments to the function it wraps:
smtp_server, port, sender_email, password and context.
These are all required for sending an email using Python's
built-in smtplib module. The send_data function also loads environment
variables from a .env file in order to keep
sensitive information such as passwords out of source code.
:param func: Pass the function that we want to decorate
:return: A function
:doc-author: Trelent
"""
def wrapper(*args, **kwargs):
load_dotenv()
smtp_server = getenv('SMTP_SERVER')
Expand All @@ -32,39 +54,84 @@ def wrapper(*args, **kwargs):

return wrapper

def __init__(self, borrowers: list, template: EmailTemplates):
self.borrowers = borrowers
def __init__(self, template: EmailTemplates, connection: DataBaseService):
self.template = template

def __str__(self):
print(self.borrowers)
self.connection = connection

@send_data
def send_passed_return_date(self, *args, **kwargs): # smtp_server, port, sender_email, password, context):
print('Before connected to SMTP server')
def send_passed_return_date(self, **kwargs):

"""
The send_passed_return_date function sends an email to the borrower
of a book that has passed its return date.
The function takes in the following arguments:
sender_email - The email address from which the reminder will be sent.
password - The password for sender_email, used to authenticate with smtp server.
smtp_server - The SMTP server through which emails are sent
(e.g., 'smtp-mail.outlook.com').
port - Port number for SMTP server (e.g., 587).
:param self: Refer to the instance of the class
:param *args: Pass a non-keyworded variable length argument list to the function
:param **kwargs: Pass a variable number of keyword arguments to a function
:return: A list of all the borrowers who have borrowed books that are overdue
"""
sender = kwargs['sender_email']
password = kwargs['password']
borrower_list = self.connection.get_borrowed_passed()

try:
print('connected to SMTP server')
#
with smtplib.SMTP_SSL(host=kwargs['smtp_server'], port=kwargs["port"], context=kwargs['context']) as server:
for borrower in self.borrowers:
today = datetime.datetime.today()
today.strftime('%Y-%m-%d')
result = borrower.return_at - today
result = str(result.days)
print(type(borrower.return_at))
# mail = self.template.send_reminder_overdue().
mail = self.template.send_reminder_overdue().substitute(sender_mail=sender,name=borrower.name, title=borrower.title,
return_at=borrower.return_at, borrower_email=borrower.email, result=result)
#@TODO wysyla pustego maila
print('To jest mail:', mail)
print('Iterating threw self.borrowers')
with smtplib.SMTP_SSL(host=kwargs['smtp_server'], port=kwargs["port"],
context=kwargs['context']) as server:
for borrower in borrower_list:
name = borrower.name
title = borrower.title
return_at = borrower.return_at
borrower_email = borrower.email
subject = "Book return reminder"
mail = self.template.send_reminder_overdue(sender, borrower_email,
name, title, return_at, subject)
server.login(sender, password)
server.sendmail(from_addr=sender, to_addrs=borrower.email, msg=mail.as_string())

except Exception as e:
print(f'Error: {e}')

def send_incoming_return_date(self, **kwargs):

"""
The send_incoming_return_date function sends an email
to the borrower of a book that is due today.
The function takes in the following arguments:
sender_email - The email address from which you want to send emails.
This should be a gmail account,
and it must have &quot;Allow less secure apps&quot;
enabled (see https://support.google.com/accounts/answer/6010255?hl=en)
:param self: Refer to the current instance of the class
:param *args: Pass a non-keyworded, variable-length argument list to the function
:param **kwargs: Pass a variable number of keyword arguments to a function
:return: None
:doc-author: Trelent
"""
sender = kwargs['sender_email']
password = kwargs['password']
borrower_list = self.connection.get_borrowed_books_by_today()

try:
with smtplib.SMTP_SSL(host=kwargs['smtp_server'], port=kwargs["port"],
context=kwargs['context']) as server:
for borrower in borrower_list:
name = borrower.name
title = borrower.title
return_at = borrower.return_at
borrower_email = borrower.email
subject = "Book return reminder"
mail = self.template.send_reminder_overdue(sender, borrower_email,
name, title, return_at, subject)
server.login(sender, password)
print('logged in')
server.sendmail(from_addr=sender, to_addrs=borrower.email, msg=mail)
print('email sent')
server.sendmail(from_addr=sender, to_addrs=borrower.email, msg=mail.as_string())

except Exception as e:
print(f'Error: {e}')
22 changes: 17 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
'''
Main module to start app
'''
import sqlite3

from mail_sender import MailSender
from database.db_service import DbManager, DataBaseService
from database.db_service import DataBaseService
from templates.template_render import EmailTemplates

connection = sqlite3.connect('database/sample_books.db')

data = DataBaseService(connection)
templates = EmailTemplates()
borrowers_list = data.get_borrowed_books_by_today()
print(borrowers_list)

email = MailSender(borrowers_list, templates)
email.send_passed_return_date()
choice = input('What would you like to do?\n'
'Press button:\n'
'1 - Send overdue notifications\n'
'2 - Send nearby notifications\n'
'3 - Exit')

if choice == '1':
email = MailSender(templates, data)
email.send_passed_return_date()
elif choice == '2':
email = MailSender(templates, data)
email.send_incoming_return_date()
else:
print('Wrong button\nStart again!')
116 changes: 76 additions & 40 deletions templates/template_render.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,82 @@
"""
This modul maintain messages used in mail_sender.py module.
Python email.message library is used here
In the future there should be jinja2 templates.
"""

from email.message import EmailMessage
from string import Template


class EmailTemplates():
"""
Class that maintan messages for following scenario:
1. Somebody passed the date of return
2. Someone's return date is later than today.
"""
@staticmethod
def send_reminder_overdue():
# mssg = Template('$name, You have borrowed $title and return date passed $return_at\n Please return it imidietly\nBest Regards\nPawel')
# return mssg
# message = EmailMessage()
# message.add_header('From', f'{sender}')
# message.add_header('To', f'{borrower.email}')
# message.add_header('Subject', 'Book return reminder')
# body = f'''
# Dear {borrower.name},
#
# You have borrowed {borrower.title} and return date passed {result}.
# Please return it imidietly.
#
# Best Regards
# Pawel
# '''
# message.set_content(body)
# message_as_string = message.as_string()

mssg = Template('''
... From: $sender_mail
... To: $borrower_email
... Subject: Book return reminder
... Dear $name, You have borrowed $title and return date passed $return_at
... Please return it imidietly.
def send_reminder_overdue(sender_mail, borrower_email, name, title, return_at, subject):

"""
The send_reminder_overdue function takes in the following arguments:
sender_mail - a string representing the email address of the sender
borrower_email - a string representing
the email address of who borrowed an item from you
name - a string representing their name (first or last)
title - a string representing what they borrowed from you
return_at - an integer that represents when they should have returned it to you by now.
:param sender_mail: Set the sender's email address
:param borrower_email: Send the email to a specific person
:param name: Personalize the message
:param title: Specify the title of the book
:param return_at: Pass the date when the book should be returned
:param subject: Set the subject of the email
:return: A message object
:doc-author: Trelent
"""
mssg = EmailMessage()
mssg.set_content(f'''
Dear {name},
... Best Regards
... Pawel ''')
You have borrowed {title} and return date passed {return_at}.
Please return it immediately.
Best Regards,
Pawel''')
mssg["Subject"] = subject
mssg["From"] = sender_mail
mssg["To"] = borrower_email

return mssg

@staticmethod
def send_reminder_nearby(sender_mail, borrower_email, name, title, return_at, subject):

"""
The send_reminder_nearby function sends an email to the borrower of a book that is due soon.
The function takes in the following arguments:
sender_mail (str): The email address of the person sending this reminder.
borrower_email (str): The email address of the person who borrowed this book.
name (str): The first name of the person who borrowed this book,
for personalization purposes.
This should be retrieved from your database using SQLAlchemy's query functionality!
:param sender_mail: Set the sender's email address
:param borrower_email: Send the email to the borrower
:param name: Personalize the message
:param title: Specify the title of the book that is borrowed
:param return_at: Get the return date of a book
:param subject: Set the subject of the email
:return: The mssg variable
:doc-author: Trelent
"""
mssg = EmailMessage()
mssg.set_content(f'''
Dear {name}, You have borrowed {title} and return date is {return_at}
Please remember to return it on time.
Best Regards
Pawel ''')
mssg["Subject"] = subject
mssg["From"] = sender_mail
mssg["To"] = borrower_email

return mssg
# @staticmethod
# def send_reminder_nearby():
# # mssg = Template('$name, You have borrowed $title and the return day is $return_at. Its about @result days from today.Please try not to overdue this dateBest Regards'
# # 'Pawel')
# # return mssg
# mssg = Template('''\
# ... From: $sender_mail
# ... Subject: Book return reminder
# ...
# ... $name, You have borrowed $title and return date will pass $return_at\n Its about $result days from today.Please try not to overdue this dateBest Regards ''')
# return mssg
Loading

0 comments on commit 2845484

Please sign in to comment.