From 03cae74a0e9da76ccf067c72aa7e9e4621075def Mon Sep 17 00:00:00 2001 From: Jacob Delgado Date: Wed, 14 Aug 2024 17:57:55 -0700 Subject: [PATCH] smtp initial setup, need to complete form to send order data --- backend/main.py | 26 ++++++++++++++++++++ backend/models.py | 17 +++++++++++++ frontend/bun.lockb | Bin 161110 -> 164666 bytes frontend/package.json | 24 ++++++++++--------- frontend/src/app/api/emails/route.ts | 26 ++++++++++++++++++++ frontend/src/components/Form/Form.tsx | 33 ++++++++++++++++++++++++++ frontend/src/lib/mail.utils.ts | 30 +++++++++++++++++++++++ 7 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 frontend/src/app/api/emails/route.ts create mode 100644 frontend/src/components/Form/Form.tsx create mode 100644 frontend/src/lib/mail.utils.ts diff --git a/backend/main.py b/backend/main.py index f263ea1..1abf7e4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -35,6 +35,32 @@ def upload(): return redirect('/') +@app.route("/mail", methods=["POST"]) +def mail(): + email = request.json["email"] + password = request.json["password"] + order = request.json["order"] + + + if email is None: + return jsonify({"error": "Unauthorized"}), 401 + + if not bcrypt.check_password_hash(user.password, password): + return jsonify({"error": "Unauthorized"}), 401 + + # Cache session with redis + session["user_id"] = user.id + + return jsonify({ + "id": user.id, + "email": user.email + }) + +@app.route("/orders", methods=["GET"]) +def orders(): + + + # Handle Images @app.route('/serve-image/', methods=['GET']) def serve_image(filename): diff --git a/backend/models.py b/backend/models.py index 0bc5b6f..b8ff370 100644 --- a/backend/models.py +++ b/backend/models.py @@ -24,6 +24,23 @@ class User(db.Model): id = db.Column(db.String(32), primary_key=True, unique=True, default=get_uuid) email = db.Column(db.String(345), unique=True) password = db.Column(db.Text, nullable=False) + +class Orders(db.Model): + __tablename__ ="orders" + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(80), unique=False, nullable=False) + email = db.Column(db.String(120), unique=False, nullable=False) + order = db.Column(db.String(345), unique=False, nullable=False) + + + + def to_json(self): + return { + "id": self.id, + "firstName":self.first_name, + "lastName":self.last_name, + "email": self.email, + } # class Category(db.Model): # __tablename__ = "categories" diff --git a/frontend/bun.lockb b/frontend/bun.lockb index f2e0eb7a45f44e1c02dc2c4dd1ec50c384f15f35..08a46ef76a1d8348c62561de0a8ed2d6dc96c9c1 100755 GIT binary patch delta 31959 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 LWIR1by#0Rw5*T3~ delta 29801 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 diff --git a/frontend/package.json b/frontend/package.json index f95751f..3a806de 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,21 +14,23 @@ "clsx": "^2.1.1", "lucide-react": "^0.427.0", "next": "14.1.4", - "react": "^18", + "nodemailer": "^6.9.14", + "react": "^18.3.1", "react-dom": "^18.3.1", "sharp": "^0.33.4", - "tailwind-merge": "^2.5.0", + "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { - "typescript": "^5", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "eslint": "^8", - "eslint-config-next": "14.1.4" + "@types/node": "^20.14.15", + "@types/nodemailer": "^6.4.15", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "autoprefixer": "^10.4.20", + "eslint": "^8.57.0", + "eslint-config-next": "14.1.4", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "typescript": "^5.5.4" } } diff --git a/frontend/src/app/api/emails/route.ts b/frontend/src/app/api/emails/route.ts new file mode 100644 index 0000000..db97005 --- /dev/null +++ b/frontend/src/app/api/emails/route.ts @@ -0,0 +1,26 @@ +export async function POST() { + const sender = { + name: 'My App', + address: 'no-reply@kevosattire.com', + } + + const recipients = [{ + name: 'John Doe', + address: 'fernando.delgado@kevosattire.com', + }] + + try{ + const result = await sendEmail({ + sender, + recipients, + subject: "Thank you for placing an order with us!", + message: "We will follow up with a Paypal invoice soon!" + }) + + return Response.json({ + accepted: result.accepted, + }) + } catch (error){ + return Response.json({message: 'Unable to send email at this time.'}, {status: 500}) + } +} \ No newline at end of file diff --git a/frontend/src/components/Form/Form.tsx b/frontend/src/components/Form/Form.tsx new file mode 100644 index 0000000..52df101 --- /dev/null +++ b/frontend/src/components/Form/Form.tsx @@ -0,0 +1,33 @@ +"use client"; +import * as React from "react"; + +const Form = () => { + const [result, setResult] = React.useState>({}); + const [loading, setLoading] = React.useState(false); + + const sendEmail = () => { + setLoading(true); + + fetch('/api/emails', { + method: 'POST' + }) + .then(response => response.json()) + .then(data => setResult(data)) + .catch(error => setResult(error)) + .finally(() => setLoading(false)) + }; + + return ( +
+
{JSON.stringify(result)}
+ + {loading &&
Processing...
} + + +
+ ); +}; + +export default Form; diff --git a/frontend/src/lib/mail.utils.ts b/frontend/src/lib/mail.utils.ts new file mode 100644 index 0000000..e9338b1 --- /dev/null +++ b/frontend/src/lib/mail.utils.ts @@ -0,0 +1,30 @@ +import nodemailer from "nodemailer"; +import Mail from "nodemailer/lib/mailer"; +import SMTPTransport from "nodemailer/lib/smtp-transport"; + +const transport = nodemailer.createTransport({ + host: process.env.MAIL_HOST, + port: process.env.MAIL_PORT, + secure: process.env.NODE_ENV !== 'development', //true + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASSWORD + }, +} as SMTPTransport.Options) + +type SendEmailDto = { + sender: Mail.Address, + recipients: Mail.Address[], + subject: string; + message: string; +} +export const sendEmail = async (dto: SendEmailDto) => { + const { sender, recipients, subject, message} = dto; + + return await transport.sendMail({ + from: sender, + to: recipients, + html: message, + text: message, + }) +} \ No newline at end of file