From c3e8684127c1384d344a648ca25579a20795e46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyril=20=C5=A0ebek?= Date: Thu, 13 Jun 2024 13:06:41 +0200 Subject: [PATCH] Fixed contact form on main page Sends data to mail Secrets from self-hosted infisical --- astro.config.mjs | 2 +- package.json | 4 + pnpm-lock.yaml | 168 ++++++++++++++++++++++++++++++++- src/components/ContactForm.tsx | 21 ++++- src/pages/api.js | 70 ++++++++++++++ 5 files changed, 255 insertions(+), 10 deletions(-) create mode 100644 src/pages/api.js diff --git a/astro.config.mjs b/astro.config.mjs index 501948a..df7602e 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -9,7 +9,7 @@ import react from "@astrojs/react"; // https://astro.build/config export default defineConfig({ - output: "hybrid", + output: "server", adapter: node({ mode: "standalone", }), diff --git a/package.json b/package.json index 72e65ea..677b4b3 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,14 @@ "@astrojs/sitemap": "^3.1.1", "@astrojs/tailwind": "^5.1.0", "@hookform/resolvers": "^3.6.0", + "@infisical/sdk": "^2.2.3", + "@paralleldrive/cuid2": "^2.2.2", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.0.4", + "@types/nodemailer": "^6.4.15", "@types/react": "^18.2.74", "@types/react-dom": "^18.2.24", "astro": "^4.5.6", @@ -30,6 +33,7 @@ "cmdk": "^1.0.0", "embla-carousel-react": "^8.0.2", "lucide-react": "^0.365.0", + "nodemailer": "^6.9.13", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 654a63d..5aaa177 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@astrojs/mdx': specifier: ^2.2.1 @@ -22,6 +26,12 @@ dependencies: '@hookform/resolvers': specifier: ^3.6.0 version: 3.6.0(react-hook-form@7.51.5) + '@infisical/sdk': + specifier: ^2.2.3 + version: 2.2.3 + '@paralleldrive/cuid2': + specifier: ^2.2.2 + version: 2.2.2 '@radix-ui/react-dialog': specifier: ^1.0.5 version: 1.0.5(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0) @@ -37,6 +47,9 @@ dependencies: '@radix-ui/react-tabs': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0) + '@types/nodemailer': + specifier: ^6.4.15 + version: 6.4.15 '@types/react': specifier: ^18.2.74 version: 18.2.74 @@ -61,6 +74,9 @@ dependencies: lucide-react: specifier: ^0.365.0 version: 0.365.0(react@18.2.0) + nodemailer: + specifier: ^6.9.13 + version: 6.9.13 react: specifier: ^18.2.0 version: 18.2.0 @@ -776,6 +792,132 @@ packages: react-hook-form: 7.51.5(react@18.2.0) dev: false + /@infisical/sdk-android-arm-eabi@2.2.3: + resolution: {integrity: sha512-eDkrjgQ1CD1UaAIbRLv4clMy4iwiprH8uMnC31d8ABdlNyvYPiC3zgy+XPuxVefnCVT2NrqM5UsPKDAIdMeOag==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-android-arm64@2.2.3: + resolution: {integrity: sha512-9EAKO+MgcHyODDobGi3iwG5n207rH2PQ0XPaC6VSZp90oN5unSTmNWK7qbElbTSf+MwrsyOJT87QTXicatzCBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-darwin-arm64@2.2.3: + resolution: {integrity: sha512-58qQA3hI9SUcRJQghiNQjt92HiWIRX1NVkWZsNN9HX6j5YaHC9hhUmJ7RopI768Bsh5jxwmyeEn9CXzFxIUA8Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-darwin-x64@2.2.3: + resolution: {integrity: sha512-AyIBGJH/EcsJrpMDgQPL4lmDAqGywn2MKB0dsOnBBwJHLdxvzra4IA9ZQHockI7kSUKu5kSA5YTk6seZ5f/BIg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-linux-arm-gnueabihf@2.2.3: + resolution: {integrity: sha512-sFGhXqckuVUPmqnFuZbX/NFlxpdAu/IHzGQKbPYsGjPnqxC+ZkCBvuyj1IpVIElL/j09pLVbMMWZv1vf+aaHmQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-linux-arm64-gnu@2.2.3: + resolution: {integrity: sha512-ppXvRBVINN7DSMLIaM3syUkYXvDVsrO0OzVgQ9ti9yYcBPOJlzrIU2H/yiXXv/m8U58jCja275i5K5y1VdjuPw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-linux-arm64-musl@2.2.3: + resolution: {integrity: sha512-/JouatsZb7KAbks682tHIRH5wMpGOoVCTBJjXNcnhV33bOxlyJ9G/UimgCYBpT9WuVhkRJKNXEQQdh7rsCsShA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-linux-x64-gnu@2.2.3: + resolution: {integrity: sha512-YH3DrvDfjmArKLrvhV+2mqoE5mY3l9cwXivqtNlcPftH5TW1MQvVq9lJEb8wIEkCNNiFYyJ2Xf8tJQDkervlYQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-linux-x64-musl@2.2.3: + resolution: {integrity: sha512-h0+14vwyigRi8aR/BfJ8LFZOJJOUa1p7fsyVUVWuTLsaDyo5l/HW4q+C3wYX2N9Jb3NyUev4lvu19WCs8W12iQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-win32-arm64-msvc@2.2.3: + resolution: {integrity: sha512-o07IXCl66/6WYDtIdPef7KeQX9aJsdmJJCMYu6K7ez9EV+nNJR7nmuhe6jdlK16kVdyfJB5lXuefCe+hWVx+HA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-win32-ia32-msvc@2.2.3: + resolution: {integrity: sha512-CXQK5N7YQ3RBVbKwx5HBGNM8LwV7/+hzN9py7C1Upv07XK0bmC6NvVrZVoYwSMDBIN3lCAy/cWASsNH+9Ve5uw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk-win32-x64-msvc@2.2.3: + resolution: {integrity: sha512-hBmKiKNQ3CK6I3Z1s+1Ix8kM2/ML5BiTRmM6EOP6iQBULMf1AmCoGzh6uO4l7gytcvixtC8Jp21+37rKjm4MLA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@infisical/sdk@2.2.3: + resolution: {integrity: sha512-UvJjOD0b3O4obdtEYh+++Pv7Jfj5qb0QMzEZrADDLQJH0bDswRgLCaCiZtvzkV6WJPw8EKM5CFyBuZOgvDLESQ==} + engines: {node: '>= 10'} + optionalDependencies: + '@infisical/sdk-android-arm-eabi': 2.2.3 + '@infisical/sdk-android-arm64': 2.2.3 + '@infisical/sdk-darwin-arm64': 2.2.3 + '@infisical/sdk-darwin-x64': 2.2.3 + '@infisical/sdk-linux-arm-gnueabihf': 2.2.3 + '@infisical/sdk-linux-arm64-gnu': 2.2.3 + '@infisical/sdk-linux-arm64-musl': 2.2.3 + '@infisical/sdk-linux-x64-gnu': 2.2.3 + '@infisical/sdk-linux-x64-musl': 2.2.3 + '@infisical/sdk-win32-arm64-msvc': 2.2.3 + '@infisical/sdk-win32-ia32-msvc': 2.2.3 + '@infisical/sdk-win32-x64-msvc': 2.2.3 + dev: false + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -842,6 +984,11 @@ packages: - supports-color dev: false + /@noble/hashes@1.4.0: + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -860,6 +1007,12 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + /@paralleldrive/cuid2@2.2.2: + resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + dependencies: + '@noble/hashes': 1.4.0 + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1621,6 +1774,12 @@ packages: resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} dev: false + /@types/nodemailer@6.4.15: + resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==} + dependencies: + '@types/node': 17.0.45 + dev: false + /@types/prop-types@15.7.12: resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} dev: false @@ -3843,6 +4002,11 @@ packages: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} dev: false + /nodemailer@6.9.13: + resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==} + engines: {node: '>=6.0.0'} + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5360,7 +5524,3 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx index 62ae8d1..b3de8e3 100644 --- a/src/components/ContactForm.tsx +++ b/src/components/ContactForm.tsx @@ -46,10 +46,21 @@ export function ContactForm({ currentLocale }) { }, }); - function onSubmit(values: z.infer) { - // Do something with the form values. - // ✅ This will be type-safe and validated. - console.log(values); + async function onSubmit(values: z.infer) { + const formData = new FormData(); + + for (const value of Object.keys(values)) { + formData.append(value, values[value]) + } + console.log(formData) + + const response = await fetch("/api", { + method: "POST", + body: formData + }); + + const data = await response.json(); + console.log(data.message) } return ( @@ -64,7 +75,7 @@ export function ContactForm({ currentLocale }) { -

{t("contact").title}

+

{t("contact").title}

{t("contact").description}
diff --git a/src/pages/api.js b/src/pages/api.js new file mode 100644 index 0000000..c5ed752 --- /dev/null +++ b/src/pages/api.js @@ -0,0 +1,70 @@ +import nodemailer from "nodemailer"; +import { createId } from '@paralleldrive/cuid2'; +import { InfisicalClient } from "@infisical/sdk"; + +const client = new InfisicalClient({ + siteUrl: import.meta.env.INFISICAL_URL, + auth: { + universalAuth: { + clientId: import.meta.env.INFISICAL_CLIENTID, + clientSecret: import.meta.env.INFISICAL_SECRET + } + } +}); + +export const POST = async ({ request }) => { + try { + var secrets = await client.listSecrets({ + environment: "dev", + projectId: import.meta.env.INFISICAL_PROJECTID, + path: "/email", + includeImports: false + }); + secrets = Object.fromEntries(secrets.map(item => [item.secretKey, item.secretValue])); + + const thisCuid = createId(); + const data = await request.formData(); + var message = { + from: `${data.get("username")} <${secrets["EMAIL"]}>`, + to: `Site Admin <${secrets["RECEIVER"]}>`, + subject: `${secrets["EMAIL_HEAD"]} | ${thisCuid}`, + text: `---\n${data.get("username")}\n${data.get("email")}\n---\n${data.get("message")}`, + html: `

---
${data.get("username")}
${data.get("email")}
---
${data.get("message")}

`, + envelope: { + from: `${data.get("username")} <${secrets["EMAIL"]}>`, + to: `Site Admin <${secrets["RECEIVER"]}>`, + } + } + var transport = nodemailer.createTransport({ + host: secrets["SMTP_SERVER"], + port: secrets["SMTP_PORT"], + secure: secrets["SMTP_SECURITY"], + auth: { + user: secrets["EMAIL"], + pass: secrets["PASSWORD"] + } + }); + + var mailResponse = await transport.sendMail(message); + console.log(mailResponse) + return new Response(JSON.stringify({ message: "Success!" }), { status: 200 }); + + } catch (error) { + console.error("Error parsing form data:", error); + return new Response(JSON.stringify({ message: "Failed to parse form data" }), { status: 400 }); + } +}; + + +/* +npm install --save @types/nodemailer +npm install --save @types/nodemailer +npm install --save @types/nodemailer +npm install --save @types/nodemailer + +další řádka + +volná řádka +další řádka +asdasdasdasdasdad dlouhá řádka asdasdasda žádný enter tady asdsadadsas +*/ \ No newline at end of file