Skip to content
This repository was archived by the owner on Dec 8, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion CodeChallenge/api/eb.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from flask import Blueprint
from hmac import compare_digest

from flask import Blueprint, request, current_app, render_template
from flask_mail import Message

from .. import core
from ..mail import mail

bp = Blueprint("awsebapi", __name__, url_prefix="/api/v1/eb")

Expand All @@ -7,3 +13,32 @@
@bp.route("/health", methods=["GET"])
def eb_health_check():
return "OK", 200


# POST request from an AWS Lambda function once per day
# any daily tasks should be placed here
@bp.route("/worker", methods=["POST"])
def worker():
try:
password = request.json["password"]
except (TypeError, KeyError):
return "", 400

if not compare_digest(password,
current_app.config["WORKER_PASSWORD"]):
return "", 401

# send daily reminder emails only while challenge is active

if core.day_number() >= 1 and not core.challenge_ended():
msg = Message("New code challenge question is unlocked!",
sender=current_app.config["MAIL_DEFAULT_SENDER"],
recipients=[current_app.config["MG_LIST"]])

msg.html = render_template("challenge_daily_email.html",
name="%recipient_fname%")
msg.extra_headers = {"List-Unsubscribe": "%unsubscribe_email%"}

mail.send(msg)

return "", 200
69 changes: 46 additions & 23 deletions CodeChallenge/api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,33 @@ def register():
f"{new_u.studentfirstname} {new_u.studentlastname}",
data=mg_vars)

msg = Message("Welcome Pilgrim! You have accepted the Code Challenge",
sender=current_app.config["MAIL_DEFAULT_SENDER"],
recipients=[new_u.parent_email])
rcpts = [new_u.parent_email]
if new_u.student_email:
rcpts.append(new_u.student_email)

# account confirmation email
# only contains login/password
confirm_email = Message("Your Code Challenge Account",
sender=current_app.config["MAIL_DEFAULT_SENDER"],
recipients=rcpts)
name = new_u.studentfirstname or new_u.parentfirstname
msg.html = render_template("challenge_account_confirm.html",
name=name)
msg.extra_headers = {"List-Unsubscribe": "%unsubscribe_email%"}
mail.send(msg)
confirm_email.html = render_template("challenge_account_confirm.html",
name=name,
username=new_u.username,
password=password)
confirm_email.extra_headers = {"List-Unsubscribe": "%unsubscribe_email%"}

# welcome email
# more in depth
welcome_email = Message("Welcome Pilgrim! You have accepted the Code Challenge",
sender=current_app.config["MAIL_DEFAULT_SENDER"],
recipients=rcpts)
welcome_email.html = render_template("challenge_welcome.html", name=name)
welcome_email.extra_headers = {"List-Unsubscribe": "%unsubscribe_email%"}

# send emails
mail.send(confirm_email)
mail.send(welcome_email)

return jsonify({"status": "success"})

Expand Down Expand Up @@ -176,29 +195,33 @@ def forgot_password():
return jsonify(status="error",
reason="no account with that email"), 400

for user in users:
multiple_accounts = len(users) > 1

for user in users: # type: Users
token = password_reset_token(user)
msg = Message(subject="Password Reset",
body="You are receiving this message because a password "
"reset request has been issued for your account. If you "
"did not make this request, you can ignore this email. "
"To reset your password, use this link within 24 hours. "
f"\n\n{current_app.config['EXTERNAL_URL']}/reset-password/{token}"
f"\n\nAccount Username: {user.username}",
recipients=[user.parent_email])

rcpts = [user.parent_email]
if user.student_email:
rcpts.append(user.student_email)

if user.studentfirstname:
name = user.studentfirstname
else:
name = user.username

msg = Message(subject="Reset your Code Challenge password",
html=render_template("challenge_password_reset.html",
name=name,
token=token,
multiple=multiple_accounts),
recipients=rcpts)

if current_app.config.get("TESTING", False):
msg.extra_headers = {"X-Password-Reset-Token": token}

if len(users) > 1:
msg.body += "\n\nNOTICE: Your email address matched multiple " \
"student accounts. Double check to make sure you " \
"are resetting the intended account, as an email " \
"was sent for all matching accounts."

mail.send(msg)

return jsonify(status="success", reason="password reset email sent", multiple=len(users) > 1)
return jsonify(status="success", reason="password reset email sent", multiple=multiple_accounts)


@bp.route("/reset-password", methods=["POST"])
Expand Down
1 change: 1 addition & 0 deletions CodeChallenge/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class DefaultConfig:
MAIL_SUPPRESS_SEND = True
MG_PRIVATE_KEY = os.getenv("MG_PRIVATE_KEY")
MG_LIST = "codechallenge@school.codewizardshq.com"
WORKER_PASSWORD = os.getenv("WORKER_PASSWORD")

# no trailing /
EXTERNAL_URL = "https://challenge.codewizardshq.com"
Expand Down
140 changes: 60 additions & 80 deletions CodeChallenge/templates/challenge_account_confirm.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>CodeWizardsHQ Code Challenge Welcome Email</title>
<title>CodeWizardsHQ Code Challenge Daily Email</title>
<style>
/* -------------------------------------
/* -------------------------------------
GLOBAL
A very basic CSS reset
------------------------------------- */
Expand Down Expand Up @@ -39,11 +39,11 @@
BODY & CONTAINER
------------------------------------- */
body {
background-color: #f6f6f6;
background-color: #353535;
}

.body-wrap {
background-color: #f6f6f6;
background-color: #353535;
width: 100%;
}

Expand All @@ -67,7 +67,6 @@
------------------------------------- */
.main {
background-color: #fff;
border: 1px solid #e9e9e9;
border-radius: 3px;
}

Expand All @@ -83,7 +82,7 @@
width: 100%;
margin-bottom: 20px;
background-color: #353535;
padding: 60px 40px;
padding: 20px;
color: #fff;
}

Expand All @@ -108,7 +107,7 @@
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 0;
margin: 20px 0 0;
line-height: 1.2em;
font-weight: 600;
}
Expand Down Expand Up @@ -278,79 +277,60 @@
<body itemscope itemtype="http://schema.org/EmailMessage">

<table class="body-wrap">
<tr>
<td></td>
<td class="container" width="800">
<div class="content">
<table class="main" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="header aligncenter">
<img src="https://challenge.codewizardshq.com/images/logo-small.png">
<h3>{{name}}, you've accepted the CodeWizardsHQ Code Challenge! </h3>
<br>
<a href="https://challenge.codewizardshq.com/login" class="btn-primary">SIGN IN</a>
</td>
</tr>
<tr>
<td class="content-wrap">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">

</td>
</tr>
<tr>
<td class="content-block">
<p>Welcome {{name}},</p>
<br/>

<p>Your mission is to defeat the evil dragon who has invaded CWHQ land. Only the bravest and brightest kid coders, like you, are prepared for this quest. </p>

<h3>How to play The Dragon Quest? </h3>
<br/>

<p>To prove yourself worthy, you must log in every day between March 1 and March 21 to answer the Code Challenge question. </p>

<p>When you have answered the final question, you will take on the mighty dragon in the boss level by writing a piece of code in Python or JavaScript. If your answer unlocks the correct answer, you are worthy to be called Code Challenge champion and a chance to win a $100 cash prize!</p>

<p>See the <a href="http://codewizardshq.com/challenge">full FAQ</a> for more answers.</p>

<h3>Who will win the challenge?</h3>
<br/>

<p>The final champions will be determined by public vote from March 23-29 so share the challenge with your family and friends.</p>

<p>Visit the <a href="http://codewizardshq.com/challenge">Code Challenge</a> page for the latest details and updates.</p>
</td>
</tr>
<tr>
<td class="content-block">
<p>Good luck and safe travels! </p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="alert alert-warning">
<a href="https://challenge.codewizardshq.com/login">Share With Friends</a>
<br/>
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_fb.jpg">
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_twitter.jpg">
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_email.jpg">
</td>
</tr>
</table>
<div class="footer">
<table width="100%">
<tr>
<td class="aligncenter content-block"><a href="%unsubscribe_url%">Unsubscribe</a> from code challenge updates.</td>
</tr>
</table>
</div></div>
</td>
<td></td>
</tr>
<tr>
<td></td>
<td class="container" width="800">
<div class="content">
<table class="main alignleft" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="header aligncenter">
<img src="https://challenge.codewizardshq.com/images/logo-small.png">
</td>
</tr>
<tr>
<td class="content-wrap">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<p><b>{{name}}, your account has been created.</b></p>
<br/>
<p>Login: {{username}}</p>
<p>Password: {{password}}</p>
<br/>
<p>Forgot your password? <a href="https://challenge.codewizardshq.com/forgot-password">Reset your password.</a></p>
</td>
</tr>
<tr>
<td>
<p><a href="https://challenge.codewizardshq.com/login">Sign in to play</a><br/>
<a href="http://codewizardshq.com/challenge">Challenge Details</a><br/>
<a href="http://codewizardshq.com/challenge">Prizes</a><br/>
<a href="http://codewizardshq.com/challenge">Frequently Asked Questions</a></p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="alert alert-warning">
<a href="https://challenge.codewizardshq.com/login">Share With Friends</a>
<br/>
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_fb.jpg">
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_twitter.jpg">
<img class="social" src="https://codewizardshq.com/wp-content/uploads/2020/01/challenge_icon_email.jpg">
</td>
</tr>
</table>
<div class="footer">
<table width="100%">
<tr>
<td class="aligncenter content-block"><a href="%unsubscribe_url%">Unsubscribe</a> from code challenge updates.</td>
</tr>
</table>
</div></div>
</td>
<td></td>
</tr>
</table>

</body>
Expand Down
Loading