diff --git a/mftp/company.py b/mftp/company.py index 84ecabf..b7ee855 100644 --- a/mftp/company.py +++ b/mftp/company.py @@ -30,6 +30,9 @@ def filter(companies, filter): for company in companies: if filter_func(company): filtered.append(company) + logging.info( + f" {company['Name']} | {company['Role']} | {company['CTC']} | {company['End_Date']} | {company['Interview_Date']}" + ) return filtered @@ -102,11 +105,17 @@ def get_new_and_modified_companies(fetched, stored, unique_key="Job_Description" if key not in stored_dict: # New entry new_entries.append(fetched_entry) + logging.info( + f" [NEW COMPANY]: {fetched_entry['Name']} | {fetched_entry['Role']} | {fetched_entry['CTC']} | {fetched_entry['End_Date']} | {fetched_entry['Interview_Date']}" + ) else: # Compare the values of the fetched entry with the stored entry stored_entry = stored_dict[key] if any(fetched_entry[k] != stored_entry.get(k) for k in fetched_entry): updated_entries.append(fetched_entry) + logging.info( + f" [MODIFIED COMPANY]: {fetched_entry['Name']} | {fetched_entry['Role']} | {fetched_entry['CTC']} | {fetched_entry['End_Date']} | {fetched_entry['Interview_Date']}" + ) return new_entries, updated_entries diff --git a/mftp/env.example.py b/mftp/env.example.py index e50aa14..5b7b4d8 100644 --- a/mftp/env.example.py +++ b/mftp/env.example.py @@ -22,7 +22,7 @@ HOSTER_EMAIL = ["hoster@kgpian.iitkgp.ac.in", "emergency.hoster@kgpian.iitkgp.ac.in"] HOSTER_NAME = "Arpit Bhardwaj" HOSTER_ROLL = ROLL_NUMBER -HOSTER_INTERESTED_ROLLS = [HOSTER_ROLL, "XXYYXXXXX", "NNAANNNNN"] +HOSTER_INTERESTED_ROLLS = ["XXYYXXXXX", "NNAANNNNN"] # SHORTLIST CONFIG (MUST) ## Maps roll number to student names diff --git a/mftp/mail.py b/mftp/mail.py index d5f36ea..0905231 100644 --- a/mftp/mail.py +++ b/mftp/mail.py @@ -5,11 +5,144 @@ from email.mime.text import MIMEText from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart -from env import FROM_EMAIL, FROM_EMAIL_PASS, BCC_EMAIL_S, HOSTER_EMAIL +from env import FROM_EMAIL, FROM_EMAIL_PASS, BCC_EMAIL_S, HOSTER_EMAIL, HOSTER_INTERESTED_ROLLS, ROLL_MAIL, ROLL_NAME -def format_shortlist(): - pass +def send_shortlists(mails, gmail_api, smtp): + print('[SENDING SHORTLIST UPDATES]', flush=True) + + if gmail_api: + import base64 + + try: + service = generate_send_service() + except Exception as e: + logging.error(f" Failed to generate GMAIL API creds ~ {str(e)}") + return + + for mail in mails: + try: + response = service.users().messages().send( + userId="me", + body={"raw": base64.urlsafe_b64encode(mail.as_bytes()).decode()} + ).execute() + except Exception as e: + logging.error(f" Failed to send request to GMAIL API : {mail['Subject']} -x-> ({mail['Bcc']}) ~ {str(e)}") + break + + if 'id' in response: + logging.info(f" [MAIL SENT] ~ {mail['Subject']} -> ({mail['Bcc']})") + else: + logging.error(f" Failed to Send Mail : {mail['Subject']} -x-> ({mail['Bcc']}) ~ {response}") + break + elif smtp: + import ssl + import smtplib + context = ssl.create_default_context() + + logging.info(" [Connecting to smtp.google.com] ...") + with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server: + logging.info(" [Connected!]") + try: + server.login(FROM_EMAIL, FROM_EMAIL_PASS) + logging.info(" [Logged In!]") + except Exception as e: + logging.error(f" Failed to log in ~ {str(e)}") + return + + for mail in mails: + try: + server.sendmail(mail["From"], mail["Bcc"].split(', '), mail.as_string()) + logging.info(f" [MAIL SENT] ~ {mail['Subject']} -> ({mail['Bcc']})") + except smtplib.SMTPException as e: + logging.error(f" Failed to Send Mail : {mail['Subject']} -x-> ({mail['Bcc']}) ~ {str(e)}") + break + + +def format_shortlists(shortlists): + print('[FORMATTING SHORTLIST UPDATES]', flush=True) + + table_body = """ + + +
+
+ + + + {columns} + + + + {rows} + +
+
+
+ + + """ + + host_interested_message = MIMEMultipart() + host_interested_message["Subject"] = "People you are interested in are shortlisted!" + host_interested_message["From"] = f'MFTP < {FROM_EMAIL} >' + host_interested_message["Bcc"] = ", ".join(HOSTER_EMAIL) + + host_interested_cols = """ + Name (count) + Company (notice_id) + """ + + def generate_row(company_shortlist): + return f""" + + {company_shortlist['company']} (#{company_shortlist['id']}) + {company_shortlist['count']} + + """ + + def generate_host_interested_row(name, company_shortlist): + return f""" + + {name} ({company_shortlist['count']}) + {company_shortlist['company']} (#{company_shortlist['id']}) + + """ + + host_interested_rows_list = [] + + mails = [] + for roll, shortlist in shortlists.items(): + if roll in HOSTER_INTERESTED_ROLLS: + name = ROLL_NAME.get(roll) + host_interested_rows_list += [generate_host_interested_row(name, company_shortlist) for company_shortlist in shortlist] + + student_mails = ROLL_MAIL.get(roll) + if student_mails is None: + continue + + message = MIMEMultipart() + message["Subject"] = "You have been shortlisted!" + message["From"] = f'MFTP < {FROM_EMAIL} >' + message["Bcc"] = ", ".join(student_mails) + + rows = ''.join(generate_row(company_shortlist) for company_shortlist in shortlist) + columns = """ + Company (notice_id) + Count + """ + + shortlist_table = table_body.format(columns=columns, rows=rows) + message.attach(MIMEText(shortlist_table, "html")) + + mails.append(message) + + host_interested_rows = ''.join(host_interested_rows_list) + host_interested_shortlist_table = table_body.format(columns=host_interested_cols, rows=host_interested_rows) + host_interested_message.attach(MIMEText(host_interested_shortlist_table, "html")) + mails.append(host_interested_message) + + return mails def send_companies(mail, gmail_api, smtp): diff --git a/mftp/mftp.py b/mftp/mftp.py index 479ff93..acbeb71 100644 --- a/mftp/mftp.py +++ b/mftp/mftp.py @@ -7,7 +7,6 @@ import company import shortlist -import logging import requests import argparse from datetime import datetime @@ -65,28 +64,10 @@ if args.gmail_api or args.smtp: _, new, modified = company.fetch(session, headers, ssoToken) - if new: - print("[NEW COMPANIES]", flush=True) - for com in new: - logging.info( - f" {com['Name']} | {com['Role']} | {com['CTC']} | {com['End_Date']} | {com['Interview_Date']}" - ) - if modified: - print("[MODIFIED COMPANIES]", flush=True) - for com in modified: - logging.info( - f" {com['Name']} | {com['Role']} | {com['CTC']} | {com['End_Date']} | {com['Interview_Date']}" - ) - filtered = [] if new + modified: filtered = company.filter(new + modified, "OPEN_N") if filtered: - for com in filtered: - logging.info( - f" {com['Name']} | {com['Role']} | {com['CTC']} | {com['End_Date']} | {com['Interview_Date']}" - ) - latest_ssoToken = session.cookies.get("ssoToken") mail_subject = "APPLY NOW! New companies opened" companies_mail = mail.format_companies( @@ -111,7 +92,9 @@ else: shortlists = shortlist.search(notices) if shortlists: - pass + shortlists_mails = mail.format_shortlists(shortlists) + if shortlists_mails: + mail.send_shortlists(shortlists_mails, args.gmail_api, args.ntfy) mails = mail.format_notices(notices) if mails: mail.send_notices(mails, args.smtp, args.gmail_api, notice_db) diff --git a/mftp/shortlist.py b/mftp/shortlist.py index 21c29c0..f1c37db 100644 --- a/mftp/shortlist.py +++ b/mftp/shortlist.py @@ -2,35 +2,66 @@ import io import PyPDF2 import logging +from env import ROLL_NAME from collections import defaultdict -from env import HOSTER_INTERESTED_ROLLS, ROLL_MAIL, ROLL_NAME def search(notices): - print('[SEARCHING SHORTLISTS]', flush=True) + notice_wise_shortlists = search_notice_wise_shortlists(notices) + if notice_wise_shortlists: + student_wise_shortlists = calc_student_wise_shortlists(notice_wise_shortlists) + return student_wise_shortlists + else: + print("[NO NEW SHORTLISTS]", flush=True) + return defaultdict(list) - shortlists = [] + +def calc_student_wise_shortlists(notice_wise_shortlists): + print("[PARSING STUDENT WISE SHORTLISTS]", flush=True) + + student_wise_shortlists = defaultdict(list) + + for notice_shortlist in notice_wise_shortlists: + for roll, shortlists in notice_shortlist.items(): + student = student_wise_shortlists[roll] + student.append(shortlists) + + for roll, shortlists in student_wise_shortlists.items(): + shortlists_str = " | ".join([ + f"{shortlist['company']} (#{shortlist['id']}) [{shortlist['count']}]" + for shortlist in shortlists + ]) + name = ROLL_NAME.get(roll) + logging.info(f" [{name} ({roll})]: {shortlists_str}") + + return student_wise_shortlists + + +def search_notice_wise_shortlists(notices): + print("[SEARCHING NOTICE WISE SHORTLISTS]", flush=True) + + notice_wise_shortlists = [] for notice in notices: # Handling Shortists in Body try: body_shortlists = search_body(notice) if body_shortlists: - shortlists.append(body_shortlists) + notice_wise_shortlists.append(body_shortlists) except Exception as e: logging.error(f" Failed to parse shortlists from notice body ~ {str(e)}") continue # Handling Shortlist in attachment try: - if 'Attachment' in notice: + if "Attachment" in notice: attachment_shortlists = search_attachment(notice) if attachment_shortlists: - shortlists.append(attachment_shortlists) + notice_wise_shortlists.append(attachment_shortlists) except Exception as e: logging.error(f" Failed to parse shortlists from attachment ~ {str(e)}") continue - return shortlists + return notice_wise_shortlists def search_body(notice): @@ -38,23 +69,20 @@ def search_body(notice): body_data = notice["BodyData"] body = body_data.decode_contents(formatter="html") - for roll in HOSTER_INTERESTED_ROLLS: + for roll in ROLL_NAME.keys(): count = body.count(roll) if count > 0: id_ = notice["UID"].split("_")[0] company = notice["Company"] name = ROLL_NAME.get(roll) - mails = ROLL_MAIL.get(roll) shortlists[roll] = { "id": id_, "company": company, - "name": name, "count": count, - "mails": mails, } logging.info( - f" [NOTICEBODY] {name} ({count}) -> {company} (#{id_})" + f" [NOTICEBODY] {name} ({roll}) [{count}] -> {company} (#{id_})" ) return shortlists @@ -64,23 +92,20 @@ def search_attachment(notice): shortlists = defaultdict(dict) attachment = notice["Attachment"] - for roll in HOSTER_INTERESTED_ROLLS: + for roll in ROLL_NAME.keys(): count = parse_pdf_bytes(attachment, roll) if count > 0: id_ = notice["UID"].split("_")[0] company = notice["Company"] name = ROLL_NAME.get(roll) - mails = ROLL_MAIL.get(roll) shortlists[roll] = { "id": id_, "company": company, - "name": name, "count": count, - "mails": mails, } logging.info( - f" [ATTACHMENT] {name} ({count}) -> {company} (#{id_})" + f" [ATTACHMENT] {name} ({roll}) [{count}] -> {company} (#{id_})" ) return shortlists