Backend & Frontend mit Mail Versand
This commit is contained in:
3
api/eslint.config.js
Normal file
3
api/eslint.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const baseConfig = require('../eslint.config.js');
|
||||
|
||||
module.exports = [...baseConfig];
|
||||
26
api/project.json
Normal file
26
api/project.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
api/src/app/app.controller.ts
Normal file
13
api/src/app/app.controller.ts
Normal 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
40
api/src/app/app.module.ts
Normal 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 {}
|
||||
41
api/src/app/app.service.ts
Normal file
41
api/src/app/app.service.ts
Normal 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
0
api/src/assets/.gitkeep
Normal file
52
api/src/assets/contact.hbs
Normal file
52
api/src/assets/contact.hbs
Normal 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
27
api/src/main.ts
Normal 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
12
api/tsconfig.app.json
Normal 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
13
api/tsconfig.json
Normal 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
20
api/webpack.config.js
Normal 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,
|
||||
}),
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user