Added ability for libcom to send emails to those with overdue books
This commit is contained in:
parent
8e592f3adc
commit
6ed3c35554
|
@ -6,6 +6,7 @@ import library.interface.browser as browser
|
|||
import library.interface.form as form
|
||||
import library.interface.help_bar as helpBar
|
||||
import library.interface.checkout as co
|
||||
import library.interface.sendemails as sendemails
|
||||
|
||||
from library import book_data
|
||||
|
||||
|
@ -186,6 +187,11 @@ def catMenu():
|
|||
cat.eventLoop()
|
||||
cat.clear()
|
||||
|
||||
def email_menu():
|
||||
w=curses.newwin(1,1)
|
||||
(my,mx)=stdscr.getmaxyx()
|
||||
sendemails.sendemails_procedure(w,hb,my//2,mx//2,mx)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
db.initializeDatabase()
|
||||
|
@ -197,6 +203,7 @@ if __name__ == "__main__":
|
|||
("",exit),
|
||||
("Check Out a Book", co_menu),
|
||||
("Return a Book", return_menu),
|
||||
("Send Overdue Email Reminders", email_menu),
|
||||
("",exit),
|
||||
("View Checked Out Books", checkedout_menu),
|
||||
("View On Shelf Books", onshelf_menu),
|
||||
|
|
|
@ -107,6 +107,13 @@ class TextEntry:
|
|||
self.value = self.value[:c] + self.value[c+1:]
|
||||
self._mv_cursor(0)
|
||||
|
||||
class PasswordEntry(TextEntry):
|
||||
def redraw(self):
|
||||
self.w.addnstr(self.y,self.x, " "*self.width, self.width)
|
||||
if self.focus:
|
||||
self.w.chgat(self.y, self.x, self.width, curses.A_UNDERLINE)
|
||||
curses.curs_set(1)
|
||||
|
||||
|
||||
|
||||
class FormWindow:
|
||||
|
@ -276,8 +283,18 @@ class FormWindow:
|
|||
if self.bt==-1:
|
||||
self.entries[self.hl].handle_input(ch)
|
||||
|
||||
class LoginForm(FormWindow):
|
||||
caption = "Enter your csclub login to access the mail server"
|
||||
blabel = "Login"
|
||||
labels = ["ID", "Password"]
|
||||
|
||||
def _make_entries(self):
|
||||
self.entries = []
|
||||
self.entries.append(TextEntry(self.w))
|
||||
self.entries.append(PasswordEntry(self.w))
|
||||
|
||||
def _return_values(self):
|
||||
return [self.entries[0].value, self.entries[1].value]
|
||||
|
||||
class BookForm(FormWindow):
|
||||
caption = "Add a Book"
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
#Import smtp for the email sending function
|
||||
import smtplib
|
||||
|
||||
#Import argparse to parse command line args
|
||||
import argparse
|
||||
|
||||
#Import sys so that we can exit when given bad command line args
|
||||
import sys
|
||||
|
||||
#Import datetime and time to check dates
|
||||
from datetime import date
|
||||
import time
|
||||
|
||||
#Import getpass for password input
|
||||
import getpass
|
||||
|
||||
#Import subprocess for validation of if a user is in a group
|
||||
import subprocess
|
||||
|
||||
#Import librarian permissions
|
||||
from library import permissions
|
||||
from library.exceptions import *
|
||||
import library.database as db
|
||||
from library.interface.form import FormWindow,BookForm, LoginForm, catch_error_with, error_form
|
||||
|
||||
#Constants
|
||||
DEFAULT_DAY_VALUE = 21
|
||||
MAX_LOGIN_ATTEMPTS = 3
|
||||
|
||||
class DaysForm(FormWindow):
|
||||
caption = "Enter the max number of days a book can be signed out for"
|
||||
blabel = "Enter"
|
||||
labels = ["Days"]
|
||||
|
||||
def _return_values(self):
|
||||
return self.entries[0].value
|
||||
|
||||
|
||||
class NameForm(FormWindow):
|
||||
caption = "Enter the name you want in the signature line for the email"
|
||||
blabel = "Enter"
|
||||
labels = ["Name"]
|
||||
|
||||
def _return_values(self):
|
||||
if self.entries[0].value is "":
|
||||
return "Librarian"
|
||||
else:
|
||||
return self.entries[0].value
|
||||
|
||||
#Private functions
|
||||
def _send_email(quest_id: str, signed_out_date: str, max_days_can_be_signed_out:int, librarianName: str, book_name_list) -> None:
|
||||
"""Sends an email to quest_id@csclub.uwaterloo.ca if the date the book
|
||||
was signed out exceeds the days it is supposed to be signed out for"""
|
||||
|
||||
email_address = quest_id + "@csclub.uwaterloo.ca"
|
||||
book_name = "".join(book_name_list)
|
||||
|
||||
#Determine the days the book has been signed out
|
||||
date_tokens = signed_out_date.split("-")
|
||||
date_signed_out = date(int(date_tokens[0]), int(date_tokens[1]), int(date_tokens[2]))
|
||||
days_signed_out = date.fromtimestamp(time.time()) - date_signed_out
|
||||
|
||||
if days_signed_out.days > max_days_can_be_signed_out:
|
||||
email_message_body = ("Hi " + quest_id + ",\n\n" + "Our records indicate that you "
|
||||
"have had the book " + book_name + " signed out for " + str(str(days_signed_out).split(" ")[:1])[2:-2] +
|
||||
" days.\n\n" + "Please return the book to the CS Club office "
|
||||
"(MC 3036) at your earliest convenience.\n\n" + "Thanks,\n\n" +
|
||||
librarianName + "\n" + "Computer Science Club | University of Waterloo\n"
|
||||
"librarian@csclub.uwaterloo.ca")
|
||||
|
||||
email_message_subject = "Overdue book: {}".format(book_name)
|
||||
email_message = "Subject: {}\n\n{}".format(email_message_subject, email_message_body)
|
||||
|
||||
server.sendmail("librarian@csclub.uwaterloo.ca", email_address, email_message)
|
||||
|
||||
#Public functions
|
||||
@permissions.check_permissions(permissions.PERMISSION_LIBCOM)
|
||||
@catch_error_with(lambda w, hb, *args : (w, hb, None))
|
||||
def sendemails_procedure(w, hb, cy, cx, mx):
|
||||
"""Procedure to send emails to those with overdue books
|
||||
|
||||
w: ncurses window for the routine
|
||||
cy,cx: centre coordinates of the screen
|
||||
mx: max width of screen
|
||||
"""
|
||||
|
||||
#Get the max days a book can be signed out for
|
||||
step1 = DaysForm(w,hb,width=mx-20)
|
||||
(r,c)=w.getmaxyx()
|
||||
w.mvwin(cy-r//2,cx-c//2)
|
||||
days = step1.event_loop()
|
||||
step1.clear()
|
||||
|
||||
#Set the days to a default value if the value given is less than 0
|
||||
if not isinstance(days, int) or days < 0:
|
||||
days = DEFAULT_DAY_VALUE
|
||||
|
||||
#Get the name of the librarain
|
||||
step2 = NameForm(w,hb,width=mx-20)
|
||||
(r,c)=w.getmaxyx()
|
||||
w.mvwin(cy-r//2,cx-c//2)
|
||||
librarianName = step2.event_loop()
|
||||
step2.clear()
|
||||
|
||||
#Set up email
|
||||
global server
|
||||
server = smtplib.SMTP_SSL("mail.csclub.uwaterloo.ca", 465)
|
||||
|
||||
#Attempt to login 3 times
|
||||
loginAttempts = 0
|
||||
while loginAttempts < MAX_LOGIN_ATTEMPTS:
|
||||
|
||||
#Get the user's login info to login to the mail server
|
||||
step3 = LoginForm(w,hb,width=mx-20)
|
||||
(r,c)=w.getmaxyx()
|
||||
w.mvwin(cy-r//2,cx-c//2)
|
||||
loginInfo = step3.event_loop()
|
||||
step3.clear()
|
||||
|
||||
csclubID = loginInfo[0]
|
||||
csclubPwd = loginInfo[1]
|
||||
|
||||
try:
|
||||
server.login(csclubID, csclubPwd)
|
||||
break
|
||||
except smtplib.SMTPAuthenticationError:
|
||||
loginAttempts += 1
|
||||
|
||||
#Check to see if login failed
|
||||
if loginAttempts >= MAX_LOGIN_ATTEMPTS:
|
||||
return ""
|
||||
|
||||
#Get the books that are signed out
|
||||
signed_out_books = db.get_checkedout_books()
|
||||
|
||||
for data in signed_out_books:
|
||||
quest_id = data["uwid"]
|
||||
date = str(data["date"]).split(" ")[0]
|
||||
book_name_with_spaces = data["title"]
|
||||
|
||||
_send_email(str(quest_id), str(date), days, str(librarianName), book_name_with_spaces)
|
||||
|
||||
#Exit from the email server
|
||||
server.quit()
|
||||
|
||||
return ""
|
||||
|
||||
|
Loading…
Reference in New Issue