Skip to content

Commit 9d1edb6

Browse files
committed
feat: added timer to show user how much time is remaining for potd submisson.
1 parent 89ed1ec commit 9d1edb6

File tree

2 files changed

+58
-56
lines changed

2 files changed

+58
-56
lines changed

src/email_service.py

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import smtplib
22
from email.message import EmailMessage
33
from . import config
4+
from datetime import datetime, timezone, timedelta
45

56
def send_email(to_email, subject, html_content):
67
"""Sends an email using the configured SMTP settings."""
7-
# Config is now loaded from config.py
8+
89
if not config.SMTP_USER or not config.SMTP_PASSWORD:
910
print(f"[ERROR] SMTP not configured. Skipping email to {to_email}")
1011
return False
@@ -25,46 +26,54 @@ def send_email(to_email, subject, html_content):
2526
return True
2627
except smtplib.SMTPAuthenticationError:
2728
print(f"\n Authentication failed for {config.SMTP_USER}.")
28-
print(" Please check that your GMAIL_APP_PASSWORD is correct.")
29+
print(" Please check that your GMAIL_APP_PASSWORD is correct.")
2930
return False
3031
except Exception as e:
3132
print(f"\n Failed to send email to {to_email}: {e}")
3233
return False
3334

3435

3536
def build_html_email(username, title, link, solved, quote=None, hints=None):
36-
"""Builds a responsive email with optional AI hints and quotes."""
37+
"""Builds a responsive email with optional AI hints, quotes, and a live countdown GIF."""
3738

3839
if hints is None:
3940
hints = []
4041

42+
timer_html = ""
43+
4144
if solved:
4245
preheader_text = f"Great job on solving {title}!"
4346
heading = f"🎉 Great Job, {username}!"
4447
subtext = f"You’ve completed today’s LeetCode challenge: <strong>{title}</strong>. Keep up the amazing momentum!"
4548
button_text = "View Challenge"
46-
button_color = "#4CAF50" # Green
47-
48-
# Use the AI quote for the footer
49+
button_color = "#4CAF50"
4950
footer = f"<em>“{quote}”</em>" if quote else "<em>Keep up the great work!</em>"
50-
5151
hints_html = ""
5252

5353
else:
5454
preheader_text = f"Don't forget to solve {title} today!"
55-
heading = f"⚠️ Hey {username}, time to code!"
55+
heading = f"Hey <a href='https://leetcode.com/u/{username}' target='_blank' style='text-decoration: none;'>{username}</a>, time to code!"
5656
subtext = f"Today's problem, <strong>{title}</strong>, is waiting for you. Don't miss out on your streak!"
5757
button_text = f"Solve '{title}' Now"
58-
button_color = "#000000" # Black
59-
60-
# Use the AI quote for the footer
58+
button_color = "#000000"
6159
footer = f"<em>“{quote}”</em>" if quote else "<em>“Small daily improvements lead to big results.” 🌱</em>"
6260

63-
# --- NEW HINTS SECTION ---
61+
deadline_iso = get_deadline_for_potd()
62+
gif_url = f"https://i.countdownmail.com/4khdvf.gif?end_date_time={deadline_iso}"
63+
64+
timer_html = f"""
65+
<tr>
66+
<td align="center" style="padding: 10px 0 10px 0;">
67+
<a href="{link}" target="_blank" style="text-decoration: none;">
68+
<img src="{gif_url}" style="width:45%!important;" border="0" alt="Time remaining to solve"/>
69+
</a>
70+
</td>
71+
</tr>
72+
"""
73+
74+
# --- Hints Section ---
6475
if hints:
65-
# Build an HTML list of hints
6676
hints_list_items = "".join([f'<li style="margin-bottom: 10px; line-height: 1.6;">{h}</li>' for h in hints])
67-
6877
hints_html = f"""
6978
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="margin-top: 30px;">
7079
<tr>
@@ -78,7 +87,7 @@ def build_html_email(username, title, link, solved, quote=None, hints=None):
7887
</table>
7988
"""
8089
else:
81-
hints_html = "" # No hints if the list is empty
90+
hints_html = ""
8291

8392
# --- HTML & CSS Template ---
8493
return f"""
@@ -91,16 +100,7 @@ def build_html_email(username, title, link, solved, quote=None, hints=None):
91100
<meta name="x-apple-disable-message-reformatting">
92101
<title>LeetCode Reminder</title>
93102
94-
<!--[if mso]>
95-
<style>
96-
* {{
97-
font-family: sans-serif !important;
98-
}}
99-
</style>
100-
<![endif]-->
101-
102103
<style>
103-
/* CSS resets and base styles */
104104
html, body {{
105105
margin: 0 auto !important;
106106
padding: 0 !important;
@@ -110,90 +110,72 @@ def build_html_email(username, title, link, solved, quote=None, hints=None):
110110
font-family: 'Helvetica Neue', Arial, sans-serif;
111111
color: #333;
112112
}}
113-
114-
/* Center the email */
115113
.wrapper {{
116114
width: 100%;
117115
background-color: #f1f1f1;
118116
}}
119-
120-
/* Main container */
121117
.container {{
122118
width: 600px;
123119
margin: 0 auto;
124120
background-color: #ffffff;
125121
border-radius: 8px;
126122
border: 1px solid #ddd;
127123
}}
128-
129-
/* Responsive styles */
130124
@media screen and (max-width: 600px) {{
131125
.container {{
132126
width: 100% !important;
133127
margin: 0 !important;
134128
border: none !important;
135-
border-radius: 0 !important;
129+
border-radius: 0 !Dimportant;
136130
}}
137131
.content {{
138132
padding: 25px !important;
139133
}}
140134
.button-link {{
141135
display: block !important;
142136
width: 100% !important;
143-
box-sizing: border-box; /* Ensures padding doesn't break width */
137+
box-sizing: border-box;
144138
}}
145139
}}
146140
</style>
147141
</head>
148142
<body style="margin: 0; padding: 0 !important; background-color: #f1f1f1;">
149-
<!-- Visually hidden preheader text -->
150143
<div style="display: none; font-size: 1px; line-height: 1px; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
151144
{preheader_text}
152145
</div>
153146
154147
<center class="wrapper">
155148
<div style="max-width: 600px; margin: 0 auto;">
156-
<!--[if (gte mso 9)|(IE)]>
157-
<table align="center" border="0" cellspacing="0" cellpadding="0" width="600" style="width:600px;">
158-
<tr>
159-
<td align="center" valign="top">
160-
<![endif]-->
161-
162149
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" class="container" style="max-width: 600px; margin: 20px auto; background: #ffffff; border-radius: 8px; border: 1px solid #ddd;">
163-
<!-- Logo/Header (Optional, but good practice) -->
164150
<tr>
165-
<td align="center" style="padding: 20px 0 10px 0; font-size: 20px; font-weight: 600; color: #000;">
151+
<td align="center" style="padding: 20px 0 15px 0; font-size: 20px; font-weight: 600; color: #000;">
166152
<img src="https://i.postimg.cc/qRgJjC6P/Leet-Code-logo-black.png" alt="" width="20px" height="20px">
167153
LeetCode Daily Reminder
168154
</td>
169155
</tr>
170-
171-
<!-- Main Content -->
156+
{timer_html}
172157
<tr>
173158
<td class="content" style="padding: 30px 40px;">
174-
<h1 style="margin: 0 0 20px 0; font-size: 24px; font-weight: 600; color: #000;">{heading}</h1>
159+
<h1 style="margin: 0 0 20px 0; font-size: 24px; font-weight: 600; color: #000; text-align: center;">{heading}</h1>
175160
<p style="margin: 0 0 30px 0; font-size: 16px; line-height: 1.6;">
176161
{subtext}
177162
</p>
178163
179-
<!-- CTA Button -->
180164
<table border="0" cellpadding="0" cellspacing="0" width="100%">
181165
<tr>
182-
<td align="left">
166+
<td align="center">
183167
<a href="{link}" target="_blank" class="button-link" style="background-color: {button_color}; color: #ffffff; font-size: 16px; font-weight: bold; text-decoration: none; padding: 14px 22px; border-radius: 5px; display: inline-block;">
184168
{button_text} &rarr;
185169
</a>
186170
</td>
187171
</tr>
188172
</table>
189173
190-
<!-- **** NEW: HINTS BLOCK INJECTED HERE **** -->
191174
{hints_html}
192175
193176
</td>
194177
</tr>
195178
196-
<!-- Footer Quote -->
197179
<tr>
198180
<td class="content" style="padding: 0 40px 30px 40px; border-top: 1px solid #eee;">
199181
<p style="margin: 20px 0 0 0; font-size: 14px; color: #555; text-align: left;">
@@ -203,17 +185,38 @@ def build_html_email(username, title, link, solved, quote=None, hints=None):
203185
</tr>
204186
</table>
205187
206-
<!--[if (gte mso 9)|(IE)]>
207-
</td>
208-
</tr>
209-
</table>
210-
<![endif]-->
211-
</div>
188+
</div>
212189
</center>
213190
</body>
214191
</html>
215192
"""
216193

194+
def get_deadline_for_potd(hour=17, minute=0):
195+
"""
196+
Returns a deadline in UTC ISO format (YYYY-MM-DDTHH:MM:SSZ)
197+
based on the current time in PST.
198+
199+
Parameters:
200+
hour (int): The hour in PST to use for the deadline (default: 17)
201+
minute (int): The minute in PST to use for the deadline (default: 0)
202+
203+
Returns:
204+
str: The deadline in UTC ISO format
205+
"""
206+
tz_pst = timezone(timedelta(hours=-8)) # PST
207+
208+
now_utc = datetime.now(timezone.utc)
209+
now_pst = now_utc.astimezone(tz_pst)
210+
211+
today_deadline_pst = now_pst.replace(hour=hour, minute=minute, second=0, microsecond=0)
212+
213+
if now_pst >= today_deadline_pst:
214+
today_deadline_pst += timedelta(days=1)
215+
216+
deadline_utc = today_deadline_pst.astimezone(timezone.utc)
217+
return deadline_utc.isoformat()
218+
219+
217220
#To Do - add a function that send admin email when bot is stopped
218221
#def stop_bot_admin_email():
219222

src/gemini_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import requests
22
import json
3-
import random
43
from . import config
54
import time
65

76
# --- Default Fallbacks ---
8-
DEFAULT_QUOTE = "Keep pushing! You’re closer than you think. 💪"
7+
DEFAULT_QUOTE = "Keep pushing! You’re closer than you think."
98
DEFAULT_HINTS = ["Try to break the problem down into smaller pieces.", "Think about the data structures that might be useful here."]
109

1110
def call_gemini_api(prompt_text, expect_json=False):

0 commit comments

Comments
 (0)