This commit is contained in:
2025-09-19 18:00:38 +02:00
commit 1f9f2dc21c
26 changed files with 1379 additions and 0 deletions
@@ -0,0 +1,88 @@
package de.champonthis.abi.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import de.champonthis.abi.buisinesslogic.ContactDataManager;
import de.champonthis.abi.buisinesslogic.ContactManager;
import de.champonthis.abi.controller.request.ContactRequest;
import de.champonthis.abi.entity.Contact;
import de.champonthis.abi.entity.ContactData;
import jakarta.validation.Valid;
@RestController
@RequestMapping("/api/v1/contact")
public class ContactController {
private final ContactManager contactManager;
private final ContactDataManager contactDataManager;
public ContactController(ContactManager contactManager, ContactDataManager contactDataManager) {
this.contactManager = contactManager;
this.contactDataManager = contactDataManager;
}
@GetMapping()
public Contact find(@RequestHeader(name = HttpHeaders.AUTHORIZATION, required = false) String authToken,
@RequestParam String name) {
Contact contact = contactManager.findByLevenshteinDistance(name);
if (contact == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
if (StringUtils.isNoneEmpty(contact.getToken()) && !contact.getToken().equals(authToken)) {
throw new ResponseStatusException(HttpStatus.ALREADY_REPORTED);
}
return contact;
}
@PostMapping()
public void update(@RequestHeader(name = HttpHeaders.AUTHORIZATION, required = false) String authToken,
@Valid @RequestBody ContactRequest request) {
Contact contact = contactManager.findByName(request.getName());
if (contact == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
if (StringUtils.isNoneEmpty(contact.getToken()) && !contact.getToken().equals(authToken)) {
throw new ResponseStatusException(HttpStatus.ALREADY_REPORTED);
}
contact.setUpdatedName(request.getUpdatedName());
boolean sendToken = false;
if (request.getCommitted() != null) {
contact.setCommitted(request.getCommitted());
if (StringUtils.isEmpty(contact.getToken())) {
String token = ContactManager.generateToken();
while (contactManager.findByToken(token) != null) {
token = ContactManager.generateToken();
}
contact.setToken(token);
sendToken = true;
}
}
contactManager.save(contact);
if (sendToken) {
ContactData contactData = contactDataManager.findByContactAndReportedBy(contact.getId(), contact.getId());
if (contactData != null) {
contactManager.sendTokenMail(contact, contactData);
}
}
}
}
@@ -0,0 +1,79 @@
package de.champonthis.abi.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import de.champonthis.abi.buisinesslogic.ContactDataManager;
import de.champonthis.abi.buisinesslogic.ContactManager;
import de.champonthis.abi.controller.request.ContactDataRequest;
import de.champonthis.abi.entity.Contact;
import de.champonthis.abi.entity.ContactData;
import jakarta.validation.Valid;
@RestController
@RequestMapping("/api/v1/contact/data")
public class ContactDataController {
private final ContactManager contactManager;
private final ContactDataManager contactDataManager;
public ContactDataController(ContactManager contactManager, ContactDataManager contactDataManager) {
this.contactManager = contactManager;
this.contactDataManager = contactDataManager;
}
@PostMapping
public ResponseEntity<ContactData> create(@Valid @RequestBody ContactDataRequest request) {
Contact contact = contactManager.findByName(request.getName());
Contact reportedBy = contactManager.findByName(request.getReportedBy());
if (contact == null || reportedBy == null) {
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
ContactData contactData = contactDataManager.findByContactAndReportedBy(contact.getId(), reportedBy.getId());
HttpStatus status = HttpStatus.OK;
boolean sendToken = false;
if (contactData == null) {
contactData = new ContactData();
contactData.setContact(contact.getId());
contactData.setReportedBy(reportedBy.getId());
status = HttpStatus.CREATED;
}
if (contact.getId().equals(reportedBy.getId())
&& StringUtils.isNotEmpty(contact.getToken())
&& (status.isSameCodeAs(HttpStatus.CREATED) || !request.getEmail().equals(contactData.getEmail()))) {
sendToken = true;
}
contactData.setEmail(request.getEmail());
contactData.setPhone(request.getPhone());
if (!contact.getId().equals(reportedBy.getId())
&& (contactData.getInviteToken() == null || StringUtils.isEmpty(contactData.getInviteToken()))) {
String inviteToken = ContactManager.generateToken();
while (contactDataManager.findByinviteToken(inviteToken) != null) {
inviteToken = ContactManager.generateToken();
}
contactData.setInviteToken(inviteToken);
contactDataManager.sendInviteMail(contact, contactData, reportedBy);
}
contactDataManager.save(contactData);
if (sendToken) {
contactManager.sendTokenMail(contact, contactData);
}
return ResponseEntity.status(status.value()).body(contactData);
}
}
@@ -0,0 +1,66 @@
package de.champonthis.abi.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import de.champonthis.abi.buisinesslogic.ContactDataManager;
import de.champonthis.abi.buisinesslogic.ContactManager;
import de.champonthis.abi.entity.Contact;
import de.champonthis.abi.entity.ContactData;
@Controller
public class FrontendController {
private final ContactManager contactManager;
private final ContactDataManager contactDataManager;
public FrontendController(ContactManager contactManager, ContactDataManager contactDataManager) {
this.contactManager = contactManager;
this.contactDataManager = contactDataManager;
}
@GetMapping("/")
public String index(
@RequestParam(required = false) String token,
@RequestParam(required = false) String invite,
Model model) {
if (token != null && !token.isEmpty()) {
Contact contact = contactManager.findByToken(token);
if (contact != null) {
model.addAttribute("token", token);
model.addAttribute("userName", contact.getName());
model.addAttribute("altName", contact.getUpdatedName());
model.addAttribute("altName", contact.getUpdatedName());
ContactData contactData = contactDataManager.findByContactAndReportedBy(contact.getId(),
contact.getId());
if (contactData != null) {
model.addAttribute("email", contactData.getEmail());
model.addAttribute("phone", contactData.getPhone());
}
}
} else if (invite != null && !invite.isEmpty()) {
ContactData contactData = contactDataManager.findByinviteToken(invite);
if (contactData != null) {
Contact contact = contactManager.findById(contactData.getContact());
if (contact != null && StringUtils.isEmpty(contact.getToken())) {
model.addAttribute("userName", contact.getName());
model.addAttribute("altName", contact.getUpdatedName());
model.addAttribute("email", contactData.getEmail());
model.addAttribute("phone", contactData.getPhone());
}
}
}
return "index";
}
@GetMapping("/imprint")
public String imprint() {
return "imprint";
}
}
@@ -0,0 +1,22 @@
package de.champonthis.abi.controller.request;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
@Data
public class ContactDataRequest {
@NotBlank(message = "name must not be empty")
private String name;
@NotBlank(message = "email must not be empty")
@Email(message = "Invalid email format")
private String email;
// Accept empty or valid phone number
@Pattern(regexp = "^$|^(\\+49|0)[1-9][0-9]{7,14}$", message = "Invalid phone number")
private String phone;
@NotBlank(message = "reportedBy must not be empty")
private String reportedBy;
}
@@ -0,0 +1,14 @@
package de.champonthis.abi.controller.request;
import de.champonthis.abi.entity.Commitment;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class ContactRequest {
@NotBlank(message = "name must not be empty")
private String name;
private String updatedName;
private Commitment committed;
}