Backend & Frontend mit Mail Versand

This commit is contained in:
2025-01-08 12:16:49 +01:00
parent c62edc9cc1
commit 368257633b
27 changed files with 15833 additions and 323 deletions

3
api/eslint.config.js Normal file
View File

@@ -0,0 +1,3 @@
const baseConfig = require('../eslint.config.js');
module.exports = [...baseConfig];

26
api/project.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "api",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "api/src",
"projectType": "application",
"tags": [],
"targets": {
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": ["build"],
"options": {
"buildTarget": "api:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "api:build:development"
},
"production": {
"buildTarget": "api:build:production"
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
import { Body, Controller, Get, Post } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post()
async sendEMail(@Body() mailInfo: {name:string,email:String,message:string}): Promise<void> {
return await this.appService.sendMail(mailInfo);
}
}

40
api/src/app/app.module.ts Normal file
View File

@@ -0,0 +1,40 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MailerModule, MailerService } from '@nestjs-modules/mailer';
import { join } from 'path';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
@Module({
imports: [MailerModule.forRootAsync({
useFactory: () => ({
transport: {
host: 'email-smtp.us-east-2.amazonaws.com',
secure: false,
port: 587,
auth: {
user: 'AKIAU6GDWVAQ2QNFLNWN',//process.env.AMAZON_USER, ,
pass: 'BDE9nZv/ARbpotim1mIOir52WgIbpSi9cv1oJoH8oEf7'//process.env.AMAZON_PASSWORD,
},
},
defaults: {
from: '"No Reply" <noreply@example.com>',
},
template: {
dir: join(__dirname, 'assets'),
adapter: new HandlebarsAdapter({
eq: function (a, b) {
return a === b;
},
}),
options: {
strict: true,
},
},
}),
}),],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

View File

@@ -0,0 +1,41 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { join } from 'path';
import { MailerService } from '@nestjs-modules/mailer';
import { z,ZodError } from 'zod';
export const SenderSchema = z.object({
name: z.string().min(6, { message: 'Name must be at least 6 characters long' }),
email: z.string().email({ message: 'Invalid email address' }),
message: z.string().min(10, { message: 'Comments must be at least 10 characters long' }),
});
@Injectable()
export class AppService {
constructor(
private mailerService: MailerService,
) {}
async sendMail(mailInfo: {name:string,email:String,message:string}): Promise<void> {
try {
SenderSchema.parse(mailInfo);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
}
throw error;
}
await this.mailerService.sendMail({
to: 'andreas.knuth@gmail.com',
from: `"Bay Area Affiliates, Inc." <bayarea@bizmatch.net>`,
subject: `Support Request from ${mailInfo.name}`,
template: 'contact.hbs',
context: {
name: mailInfo.name,
email: mailInfo.email,
message: mailInfo.message
},
});
}
}

0
api/src/assets/.gitkeep Normal file
View File

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Neue Nachricht von {{name}}</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333333;
}
.container {
width: 80%;
margin: auto;
padding: 20px;
border: 1px solid #dddddd;
border-radius: 5px;
background-color: #f9f9f9;
}
.header {
text-align: center;
padding-bottom: 20px;
border-bottom: 1px solid #dddddd;
}
.content {
margin-top: 20px;
}
.footer {
margin-top: 30px;
text-align: center;
font-size: 0.9em;
color: #777777;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>Neue Nachricht von {{name}}</h2>
</div>
<div class="content">
<p><strong>Name:</strong> {{name}}</p>
<p><strong>Email:</strong> {{email}}</p>
<p><strong>Nachricht:</strong></p>
<p>{{message}}</p>
</div>
<div class="footer">
<p>Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht direkt auf diese Nachricht.</p>
</div>
</div>
</body>
</html>

27
api/src/main.ts Normal file
View File

@@ -0,0 +1,27 @@
/**
* This is not a production server yet!
* This is only a minimal backend to get started.
*/
import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app/app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
app.enableCors({
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowedHeaders: 'Content-Type, Accept, Authorization, x-hide-loading',
});
const port = 3000;//process.env.PORT || 3000;
await app.listen(port);
Logger.log(
`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`
);
}
bootstrap();

12
api/tsconfig.app.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../dist/out-tsc",
"module": "ES2015",
"types": ["node"],
"emitDecoratorMetadata": true,
"target": "es2021"
},
"exclude": [ "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}

13
api/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
],
"compilerOptions": {
"esModuleInterop": true
}
}

20
api/webpack.config.js Normal file
View File

@@ -0,0 +1,20 @@
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
const { join } = require('path');
module.exports = {
output: {
path: join(__dirname, '../dist/api'),
},
plugins: [
new NxAppWebpackPlugin({
target: 'node',
compiler: 'tsc',
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
assets: ['./src/assets'],
optimization: false,
outputHashing: 'none',
generatePackageJson: true,
}),
],
};