Users can upload photos
This commit is contained in:
2
.idea/PortfolioProject.iml
generated
2
.idea/PortfolioProject.iml
generated
@@ -4,7 +4,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.10 (BreadApp)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (BreadApp)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
||||||
3
mail.txt
Normal file
3
mail.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
$to == jenseluc@oregonstate.edu
|
||||||
|
$subject == whole wheat loaf
|
||||||
|
$message == whole wheat loaf; Num loaves: 1; AP Flour: 100 grams; WW Flour: 400 grams; Rye Flour: 0 grams; Water: 300 grams; Salt: 20 grams; Yeast: 2 grams; Starter: 10 grams;
|
||||||
87
mailer.py
Normal file
87
mailer.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
from mailjet_rest import Client
|
||||||
|
|
||||||
|
api_key = '9aa5c72ce9c248d0570aa1e6cabdc9ab'
|
||||||
|
api_secret = '9bed4b34d09b8e19017768cc8264479e'
|
||||||
|
mailjet = Client(auth=(api_key, api_secret), version='v3.1')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Sending ======>")
|
||||||
|
# read maile.txt
|
||||||
|
with open('mail.txt', 'rt') as infile:
|
||||||
|
text = infile.read()
|
||||||
|
|
||||||
|
# when text start with '$' it is the key and the rest is the value
|
||||||
|
# split the text into a list of lines
|
||||||
|
lines = text.split('\n')
|
||||||
|
# loop through the lines
|
||||||
|
theMail = {}
|
||||||
|
to = ""
|
||||||
|
subject = ""
|
||||||
|
body = ""
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
for line in lines:
|
||||||
|
# if the line starts with '$'
|
||||||
|
|
||||||
|
if line.startswith('$'):
|
||||||
|
# split the line into key and value
|
||||||
|
key, value = line.split(' ', 1)
|
||||||
|
|
||||||
|
# if the key is 'email'
|
||||||
|
if key == '$to':
|
||||||
|
to = value.replace("==", "").strip()
|
||||||
|
elif key == '$subject':
|
||||||
|
|
||||||
|
subject = value.replace("==", "").strip()
|
||||||
|
elif key == '$message':
|
||||||
|
body = value.replace("==", "").strip()
|
||||||
|
elif line.startswith('#'):
|
||||||
|
#reset variables
|
||||||
|
to = ""
|
||||||
|
subject = ""
|
||||||
|
body = ""
|
||||||
|
|
||||||
|
if to != "" and subject != "" and body != "":
|
||||||
|
|
||||||
|
#add them to the dictionary
|
||||||
|
theMail[i] = {'to': to, 'subject': subject, 'body': body}
|
||||||
|
i += 1
|
||||||
|
# reset the variables
|
||||||
|
to = ""
|
||||||
|
subject = ""
|
||||||
|
body = ""
|
||||||
|
# if #end is found, reset the variables
|
||||||
|
# loop through the dictionary
|
||||||
|
for key, value in theMail.items():
|
||||||
|
# send the email
|
||||||
|
send_email(value['to'], value['subject'], value['body'])
|
||||||
|
# print(value['to'])
|
||||||
|
# print(value['subject'])
|
||||||
|
# print(value['body'])
|
||||||
|
# print(theMail)
|
||||||
|
|
||||||
|
def send_email(email, subject, body):
|
||||||
|
data = {
|
||||||
|
'Messages': [
|
||||||
|
{
|
||||||
|
"From": {
|
||||||
|
"Email": "khansom@oregonstate.edu",
|
||||||
|
"Name": "Soman Khan"
|
||||||
|
},
|
||||||
|
"To": [
|
||||||
|
{
|
||||||
|
"Email": email,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Subject": subject,
|
||||||
|
"TextPart": "Greetings!",
|
||||||
|
"HTMLPart": body,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
result = mailjet.send.create(data=data)
|
||||||
|
print(result.status_code)
|
||||||
|
print(result.json())
|
||||||
|
# call main
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
72
main.py
72
main.py
@@ -5,11 +5,15 @@ Last updated 5/12 for Assignment 1
|
|||||||
"""
|
"""
|
||||||
from flask import Flask, redirect, render_template, request, send_file
|
from flask import Flask, redirect, render_template, request, send_file
|
||||||
from recipe import Recipe, RecipeBook
|
from recipe import Recipe, RecipeBook
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
book = RecipeBook()
|
book = RecipeBook()
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def home():
|
def home():
|
||||||
return render_template("index.html")
|
return render_template("index.html")
|
||||||
@@ -24,23 +28,79 @@ def recipes_page():
|
|||||||
return render_template("recipes.html", content=recipes)
|
return render_template("recipes.html", content=recipes)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/recipes/<_id>', methods=['GET', 'POST'])
|
@app.route('/recipes/<_id>/email', methods=['GET', 'POST'])
|
||||||
def recipe_page(_id):
|
def email_page(_id):
|
||||||
recipe = book.find_by_id(str(_id))
|
recipe = book.find_by_id(str(_id))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
addr = request.form.get('email')
|
||||||
|
subject = recipe.get_name()
|
||||||
|
message = f"{subject}; " \
|
||||||
|
f"Num loaves: {recipe.get_num_loaves()};"
|
||||||
|
ingredients = recipe.get_ingredients()
|
||||||
|
for item in ingredients:
|
||||||
|
message += f" {item}: {ingredients[item]} grams;"
|
||||||
|
|
||||||
|
body = f"$to == {addr}\n" \
|
||||||
|
f"$subject == {subject}\n" \
|
||||||
|
f"$message == {message}"
|
||||||
|
|
||||||
|
with open('mail.txt', 'wt') as txt_file:
|
||||||
|
txt_file.write(body)
|
||||||
|
|
||||||
|
subprocess.call(['python', 'mailer.py'])
|
||||||
|
|
||||||
|
return redirect('/recipes')
|
||||||
|
|
||||||
|
return render_template('email.html', content=recipe)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/recipes/<_id>', methods=['GET', 'POST'])
|
||||||
|
def recipe_page(_id):
|
||||||
|
recipe = book.find_by_id(_id)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
# user wants to scale their recipe
|
||||||
if 'scale' in request.form:
|
if 'scale' in request.form:
|
||||||
scale = request.form.get('scale')
|
scale = request.form.get('scale')
|
||||||
new = recipe.scale(scale)
|
new = recipe.scale(scale)
|
||||||
new_id = book.add_recipe(new)
|
new_id = book.add_recipe(new)
|
||||||
return redirect(f'/recipes/{new_id}')
|
return redirect(f'/recipes/{new_id}')
|
||||||
|
elif 'photo' in request.files:
|
||||||
|
# user wants to add a photo
|
||||||
|
f = request.files['photo']
|
||||||
|
f.save(os.path.join('static', f"image_{_id}.jpg"))
|
||||||
|
# return "Success"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# user wants to download a pdf
|
||||||
path = write_txt(_id)
|
path = write_txt(_id)
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
return send_file(path, as_attachment=True)
|
return send_file(path, as_attachment=True)
|
||||||
|
|
||||||
return render_template("recipe.html", content=recipe, _id=_id)
|
# find all associated images
|
||||||
|
recipe_photos = []
|
||||||
|
all_photos = os.listdir('static')
|
||||||
|
for photo in all_photos:
|
||||||
|
if 'jpg' in photo:
|
||||||
|
if get_num(photo) == int(_id):
|
||||||
|
recipe_photos.append(photo)
|
||||||
|
|
||||||
|
return render_template("recipe.html", content=recipe, _id=_id, photos=recipe_photos)
|
||||||
|
|
||||||
|
|
||||||
|
def get_num(path: str) -> int:
|
||||||
|
"""
|
||||||
|
:param path: must be formatted: "image_XXX.jpg" where XXX is the id of the recipe with any number of digits
|
||||||
|
:return: integer of the found id number
|
||||||
|
"""
|
||||||
|
num = ""
|
||||||
|
for i in range(6, len(path)):
|
||||||
|
if path[i] == '.':
|
||||||
|
break
|
||||||
|
num += path[i]
|
||||||
|
|
||||||
|
return int(num)
|
||||||
|
|
||||||
|
|
||||||
def write_txt(_id):
|
def write_txt(_id):
|
||||||
@@ -55,10 +115,6 @@ def write_txt(_id):
|
|||||||
return f"recipe{_id}.pdf"
|
return f"recipe{_id}.pdf"
|
||||||
|
|
||||||
|
|
||||||
# app.route('/recipes/<id>/download')
|
|
||||||
# def
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/recipes/<_id>/delete')
|
@app.route('/recipes/<_id>/delete')
|
||||||
def delete_recipe(_id):
|
def delete_recipe(_id):
|
||||||
book.find_and_delete(_id)
|
book.find_and_delete(_id)
|
||||||
@@ -80,4 +136,4 @@ def add_recipe():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=False)
|
app.run(debug=True)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
recipe1.pdf
|
0
|
||||||
21
recipes.json
21
recipes.json
@@ -12,12 +12,25 @@
|
|||||||
"Starter": 0
|
"Starter": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"2": {
|
||||||
"quantity": "2",
|
"quantity": "1",
|
||||||
"name": "Sourdough * 1.0",
|
"name": "Sandwich Loaf",
|
||||||
"ingredients": {
|
"ingredients": {
|
||||||
"AP Flour": 500,
|
"AP Flour": 500,
|
||||||
"WW Flour": 500,
|
"WW Flour": 0,
|
||||||
|
"Rye Flour": 0,
|
||||||
|
"Water": 250,
|
||||||
|
"Salt": 20,
|
||||||
|
"Yeast": 10,
|
||||||
|
"Starter": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"quantity": "1",
|
||||||
|
"name": "tobi",
|
||||||
|
"ingredients": {
|
||||||
|
"AP Flour": 100,
|
||||||
|
"WW Flour": 0,
|
||||||
"Rye Flour": 0,
|
"Rye Flour": 0,
|
||||||
"Water": 0,
|
"Water": 0,
|
||||||
"Salt": 0,
|
"Salt": 0,
|
||||||
|
|||||||
18
templates/email.html
Normal file
18
templates/email.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}{{content.get_name()}}{% endblock %}
|
||||||
|
|
||||||
|
{% block html_head %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ content.get_name() }}</h1>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<label for="email">Email: </label>
|
||||||
|
<input name="email" id="email" type="email">
|
||||||
|
<button type="submit">Send!</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
<h1>{{ content.get_name() }} Recipe</h1>
|
<h1>{{ content.get_name() }} Recipe</h1>
|
||||||
|
|
||||||
|
|
||||||
<p>Number of loaves: {{ content.get_num_loaves() }}</p>
|
<p>Number of loaves: {{ content.get_num_loaves() }}</p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@@ -32,10 +31,27 @@
|
|||||||
<button type="submit">Go!</button>
|
<button type="submit">Go!</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form name="photo upload" id="photo upload" method="post" enctype="multipart/form-data">
|
||||||
|
<label for="photo">Upload a Photo: </label>
|
||||||
|
<input id="photo" type="file" name="photo">
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
<input type="button" onclick="location.href='/recipes/{{_id}}/delete'" value=Delete />
|
<input type="button" onclick="location.href='/recipes/{{_id}}/delete'" value=Delete />
|
||||||
<form method="post">
|
|
||||||
|
<form name="download" id="download" method="post">
|
||||||
<button type="submit">Download</button>
|
<button type="submit">Download</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<a href="/recipes/{{_id}}/email">Email me!</a>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!--<p>Photos: {{photos}}</p>-->
|
||||||
|
{% for photo in photos %}
|
||||||
|
<!-- <p>{{photo}}</p>-->
|
||||||
|
<img src="{{ url_for('static', filename=photo) }}" width="250" alt="bread photo">
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user