feat(fullstack): Add contact form

This commit is contained in:
2026-02-08 18:21:07 +01:00
parent 43aef3b5b1
commit 36132a3bef
12 changed files with 420 additions and 11 deletions

View File

@@ -0,0 +1,23 @@
package com.betriebsratkanzlei.legalconsenthub.contact
import com.betriebsratkanzlei.legalconsenthub_api.api.ContactApi
import com.betriebsratkanzlei.legalconsenthub_api.model.ContactMessageDto
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.RestController
@RestController
class ContactController(
private val contactService: ContactService,
) : ContactApi {
@PreAuthorize(
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
)
override fun sendContactMessage(contactMessageDto: ContactMessageDto): ResponseEntity<Unit> {
contactService.sendContactMessage(
subject = contactMessageDto.subject,
message = contactMessageDto.message,
)
return ResponseEntity.noContent().build()
}
}

View File

@@ -0,0 +1,58 @@
package com.betriebsratkanzlei.legalconsenthub.contact
import com.betriebsratkanzlei.legalconsenthub.email.EmailService
import com.betriebsratkanzlei.legalconsenthub.user.UserService
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.thymeleaf.TemplateEngine
import org.thymeleaf.context.Context
@Service
class ContactService(
private val emailService: EmailService,
private val userService: UserService,
private val templateEngine: TemplateEngine,
) {
private val logger = LoggerFactory.getLogger(ContactService::class.java)
companion object {
private const val CONTACT_EMAIL = "kontakt@gremiumhub.de"
}
fun sendContactMessage(
subject: String,
message: String,
) {
val currentUser = userService.getCurrentUser()
val emailBody =
buildContactEmail(
senderName = currentUser.name,
senderEmail = currentUser.email ?: "Keine E-Mail angegeben",
subject = subject,
message = message,
)
emailService.sendEmail(
to = CONTACT_EMAIL,
subject = "Kontaktanfrage: $subject",
body = emailBody,
)
logger.info("Contact message sent from user ${currentUser.keycloakId} with subject: $subject")
}
private fun buildContactEmail(
senderName: String,
senderEmail: String,
subject: String,
message: String,
): String {
val context = Context()
context.setVariable("senderName", senderName)
context.setVariable("senderEmail", senderEmail)
context.setVariable("subject", subject)
context.setVariable("message", message)
return templateEngine.process("email/contact_message", context)
}
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background-color: #4F46E5; color: white; padding: 20px; border-radius: 5px 5px 0 0; }
.content { background-color: #f9fafb; padding: 20px; }
.message-box { background-color: white; padding: 15px; border-radius: 5px; border: 1px solid #e5e7eb; margin-top: 15px; }
.footer { color: #6b7280; font-size: 12px; margin-top: 20px; }
.info-label { font-weight: bold; color: #374151; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>Neue Kontaktanfrage</h2>
</div>
<div class="content">
<p>Eine neue Kontaktanfrage wurde über GremiumHub gesendet:</p>
<ul>
<li><span class="info-label">Absender:</span> <span th:text="${senderName}"></span></li>
<li><span class="info-label">E-Mail:</span> <span th:text="${senderEmail}"></span></li>
<li><span class="info-label">Betreff:</span> <span th:text="${subject}"></span></li>
</ul>
<p class="info-label">Nachricht:</p>
<div class="message-box" th:utext="${message}"></div>
</div>
<div class="footer">
<p>Diese E-Mail wurde automatisch von GremiumHub gesendet.</p>
</div>
</div>
</body>
</html>