mail util
This commit is contained in:
parent
ffe4075157
commit
4a0c307f13
5 changed files with 237 additions and 4 deletions
46
flask_app.py
46
flask_app.py
|
@ -16,7 +16,8 @@ from flask_sqlalchemy import SQLAlchemy
|
|||
from werkzeug.utils import secure_filename
|
||||
|
||||
from config_hackWPI import (api_keys, SERVER_LISTEN_ADDR, SERVER_PORT, WAITLIST_LIMIT, HACKATHON_TIME,
|
||||
ALLOWED_EXTENSIONS, REGISTRATION_OPEN)
|
||||
ALLOWED_EXTENSIONS, REGISTRATION_OPEN, MCE_API_KEY)
|
||||
from mail import send_message
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_pyfile('config.py')
|
||||
|
@ -241,9 +242,46 @@ def register():
|
|||
# Finally, send them to their dashboard
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
@app.route('/mail')
|
||||
def mail():
|
||||
if not is_admin():
|
||||
return redirect(url_for('register'))
|
||||
return render_template('mail.html', MCE_API_KEY=MCE_API_KEY, NUM_HACKERS=len(admin(True)))
|
||||
|
||||
@app.route('/send', methods=['POST'])
|
||||
def send():
|
||||
if not is_admin():
|
||||
return "Not Authorized", 401
|
||||
args = request.json
|
||||
print(args)
|
||||
recipients = args.get("recipients") or ""
|
||||
subject = args.get("subject") or ""
|
||||
html = args.get("html") or ""
|
||||
text = args.get("text") or ""
|
||||
|
||||
to = []
|
||||
if(recipients == "org"):
|
||||
to = ["hack@wpi.edu"]
|
||||
elif(recipients == "admin"):
|
||||
to = ["acm-sysadmin@wpi.edu"]
|
||||
elif(recipients == "all"):
|
||||
to = [x["email"] for x in admin(True)]
|
||||
elif(recipients == "wpi"):
|
||||
to = [ x["email"] for x in admin(True) if "wpi.edu" in x["email"] or \
|
||||
(x["school"] and ("WPI" in x["school"]["name"] or "Worcester Polytechnic" in x["school"]["name"])) ]
|
||||
|
||||
# return str(to)
|
||||
send_message(to, subject, html, text)
|
||||
return "Message sent successfully to {0} recipients".format(len(to))
|
||||
|
||||
@app.route('/hackers', methods=['GET'])
|
||||
def hackers():
|
||||
if not is_admin():
|
||||
return redirect(url_for('register'))
|
||||
return jsonify(admin(True))
|
||||
|
||||
@app.route('/admin', methods=['GET'])
|
||||
def admin():
|
||||
def admin(return_hackers=False):
|
||||
# Displays total registration information...
|
||||
# As Firebase could not be used with MyMLH, use PubNub to simulate the realtime database...
|
||||
|
||||
|
@ -314,6 +352,8 @@ def admin():
|
|||
'special_needs': obj.special_needs,
|
||||
'school': hacker['school'] if 'school' in hacker else 'NULL'
|
||||
})
|
||||
if(return_hackers):
|
||||
return hackers
|
||||
|
||||
return render_template('admin.html', hackers=hackers, total_count=total_count, waitlist_count=waitlist_count,
|
||||
check_in_count=check_in_count, shirt_count=shirt_count, female_count=female_count,
|
||||
|
@ -538,7 +578,7 @@ def is_self(mlh_id):
|
|||
return False
|
||||
return True
|
||||
|
||||
|
||||
# TODO: Migrate to new mail module
|
||||
def send_email(to, subject, body):
|
||||
print("Email sent to: " + to)
|
||||
body += '\nPlease let your friends know about the event as well!\n'
|
||||
|
|
45
mail/__init__.py
Normal file
45
mail/__init__.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
import smtplib
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from config_hackWPI import (api_keys)
|
||||
|
||||
user = api_keys['smtp_email']['user']
|
||||
bcc = api_keys['smtp_email']['bcc']
|
||||
reply = api_keys['smtp_email']['reply']
|
||||
sender = api_keys['smtp_email']['sender']
|
||||
smtp_server = api_keys['smtp_email']['smtp_server']
|
||||
smtp_port = api_keys['smtp_email']['smtp_port']
|
||||
|
||||
def send_message(recipients, subject="", html="", text=""):
|
||||
print("Sending email to {0} with subject {1}".format(recipients, subject))
|
||||
# Create message container - the correct MIME type is multipart/alternative.
|
||||
msg = MIMEMultipart('alternative')
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = sender
|
||||
msg.add_header('reply-to', reply)
|
||||
|
||||
# Record the MIME types of both parts - text/plain and text/html.
|
||||
part1 = MIMEText(text, 'plain')
|
||||
part2 = MIMEText(html, 'html')
|
||||
|
||||
# Attach parts into message container.
|
||||
# According to RFC 2046, the last part of a multipart message, in this case
|
||||
# the HTML message, is best and preferred.
|
||||
msg.attach(part1)
|
||||
msg.attach(part2)
|
||||
|
||||
server = smtplib.SMTP(smtp_server, smtp_port)
|
||||
# Enable TLS if we're using secure SMTP
|
||||
if(smtp_port > 25):
|
||||
server.starttls()
|
||||
# Login if we're using server with auth
|
||||
if ('pass' in api_keys['smtp_email']):
|
||||
server.login(user, api_keys['smtp_email']['pass'])
|
||||
|
||||
server.sendmail(sender, recipients, msg.as_string())
|
||||
server.quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
send_message(["acm-sysadmin@wpi.edu"], "Test Subject", "<b>Test HTML</b>", "Test text")
|
47
static/css/mail.css
Normal file
47
static/css/mail.css
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* For best practice, move CSS below to an external CSS file. */
|
||||
@keyframes fadeinall {
|
||||
0% {
|
||||
opacity: 1; }
|
||||
97% {
|
||||
opacity: 0; }
|
||||
98% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0); }
|
||||
99% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateY(-100%);
|
||||
transform: translateY(-100%); }
|
||||
100% {
|
||||
opacity: 0;
|
||||
z-index: -1; } }
|
||||
#loader {
|
||||
opacity: 1;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
background-color: #fff;
|
||||
z-index: 999;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation: fadeinall 1s normal both;
|
||||
animation: fadeinall 1s normal both;
|
||||
-webkit-animation-delay: 0.3s;
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
#loader {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #222222;
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
input, button, select, textarea {
|
||||
border-radius: 5px;
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit bfb9d7799fbb8630f4351f043a05aa617964becf
|
||||
Subproject commit b2a60294b8f9d37d8c486cd817f8260cc860caad
|
101
templates/mail.html
Normal file
101
templates/mail.html
Normal file
|
@ -0,0 +1,101 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>🍪CookieMailer</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta name="description" content="" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<meta name="theme-color" content="">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/mail.css" />
|
||||
<script src="https://cdn.tiny.cloud/1/{{MCE_API_KEY}}/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script></head>
|
||||
<body>
|
||||
<div id="loader"></div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div id="root" class="col">
|
||||
<h2>🍪CookieMailer</h2>
|
||||
<label for="recipients">To: </label>
|
||||
<br/>
|
||||
<select id="recipients" name="recipients">
|
||||
<option value="admin">Test Email (SysAdmin)</option>
|
||||
<option value="org">Test Email (Organizers)</option>
|
||||
<!-- <option value="wpi">WPI Only</option> -->
|
||||
<option value="all">All Participants ({{NUM_HACKERS}})</option>
|
||||
</select>
|
||||
<br/>
|
||||
<label for="subject">Subject: </label>
|
||||
<br/>
|
||||
<input id="subject" name="subject" width="100%" type="text" value="Hack@WPI" />
|
||||
<br/>
|
||||
<br/>
|
||||
<textarea id="content" name="content">
|
||||
Message
|
||||
<br/>
|
||||
<br/>
|
||||
Best,<br/>
|
||||
<b>Hack@WPI Team</b><br/>
|
||||
<i><a href="mailto:hack@wpi.edu">hack@wpi.edu</a></i><br/>
|
||||
<img height="75px" width="75px" src="https://media.discordapp.net/attachments/829437603291856938/930311998057635880/hack317-min.png">
|
||||
</textarea>
|
||||
<br/>
|
||||
<br/>
|
||||
<input type="button" onClick="send()" value="Send"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript">
|
||||
window.onload = function(){
|
||||
tinymce.init({
|
||||
selector: '#content',
|
||||
plugins: 'advlist,link'
|
||||
});
|
||||
|
||||
setTimeout(function(){
|
||||
document.getElementById("loader").remove();
|
||||
},1000);
|
||||
};
|
||||
|
||||
function send() {
|
||||
let rec = document.getElementById("recipients").value;
|
||||
let subject = document.getElementById("subject").value;
|
||||
let text = tinyMCE.activeEditor.getContent({ format: 'text' });
|
||||
let html = tinyMCE.activeEditor.getContent({ format: 'html' });
|
||||
|
||||
let body = {
|
||||
"recipients": rec,
|
||||
"subject": subject,
|
||||
"text": text,
|
||||
"html": html
|
||||
}
|
||||
|
||||
console.log("Sending Email:"+JSON.stringify(body))
|
||||
|
||||
const headers = [
|
||||
["Content-Type", "application/json"],
|
||||
];
|
||||
|
||||
if((rec != "all" && window.confirm("Send test email?")) || (rec == "all" && window.confirm("Send email to {{NUM_HACKERS}} recipients?"))) {
|
||||
fetch('/send', {method: 'POST', body: JSON.stringify(body), headers: headers}).then(async (res) => {
|
||||
window.alert(await res.text());
|
||||
}).catch((err) => {
|
||||
window.alert("Error sending message - see console for details");
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
window.alert("Nothing was sent");
|
||||
}
|
||||
|
||||
// fetch('/send', {method: 'POST', body: JSON.stringify(body), headers: headers}).then(async (res) => {
|
||||
// alert("Message sent");
|
||||
// document.body.innerHTML = await res.text()
|
||||
// }).catch((err) => {
|
||||
// alert("Error sending message");
|
||||
// document.body.innerHTML = err;
|
||||
// })
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Add table
Reference in a new issue