email theu the server

This commit is contained in:
2025-12-10 16:41:27 -05:00
parent 2049f62f99
commit c88527d9d1
14 changed files with 349 additions and 20 deletions

29
pom.xml
View File

@@ -38,14 +38,15 @@
<scm>
<connection></connection>
<developerConnection>scm:git:https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git</developerConnection>
<developerConnection>scm:git:https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
</developerConnection>
<tag/>
<url>ssh://git@gitea.gofwd.group:2225/Forward_Group/ballistic-builder-spring.git</url>
</scm>
<properties>
<java.version>17</java.version>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
@@ -63,6 +64,25 @@
</dependency>
-->
<!-- JSON Web Tokens (JJWT) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- Spring Mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@@ -155,8 +175,9 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<source>21</source>
<target>21</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>

View File

@@ -0,0 +1,13 @@
CREATE TABLE email_requests (
id BIGSERIAL PRIMARY KEY,
recipient VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
body TEXT,
sent_at TIMESTAMP,
status VARCHAR(50) NOT NULL,
error_message TEXT,
created_at TIMESTAMP NOT NULL
);
CREATE INDEX idx_email_requests_status ON email_requests(status);
CREATE INDEX idx_email_requests_created_at ON email_requests(created_at);

View File

@@ -24,12 +24,12 @@ public class ApiResponse<T> {
this.timestamp = LocalDateTime.now();
}
public static <T> ApiResponse<T> success(T data, String message) {
String[] msg = {message};
return new ApiResponse<>(API_SUCCESS, msg, data);
public static <T> ApiResponse<T> error(String message, T data) {
String[] msg = {message}; // ✅ Include the message
return new ApiResponse<>(API_ERROR, msg, data);
}
public static <T> ApiResponse<T> success(T data) {
public static <T> ApiResponse<T> success(T data, String emailSentSuccessfully) {
String[] msg = {};
return new ApiResponse<>(API_SUCCESS, msg, data);
}
@@ -42,6 +42,7 @@ public class ApiResponse<T> {
return new ApiResponse<>(API_ERROR, msg, null);
}
public String[] getMessages() {
return messages;
}

View File

@@ -1,11 +1,17 @@
/*
package group.goforward.battlbuilder.configuration;
// @Configuration
// public class PasswordConfig {
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
// @Bean
// public PasswordEncoder passwordEncoder() {
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// // BCrypt default password
// return new BCryptPasswordEncoder();
// }
// }
return new BCryptPasswordEncoder();
}
}*/

View File

@@ -9,11 +9,11 @@ import java.util.List;
@RestController
@RequestMapping("/api/admin/part-categories")
@CrossOrigin // keep it loose for now, you can tighten origins later
public class PartCategoryAdminController {
public class AdminPartCategoryController {
private final PartCategoryRepository partCategories;
public PartCategoryAdminController(PartCategoryRepository partCategories) {
public AdminPartCategoryController(PartCategoryRepository partCategories) {
this.partCategories = partCategories;
}

View File

@@ -13,11 +13,11 @@ import java.util.List;
@RestController
@RequestMapping("/api/platforms")
@CrossOrigin
public class PlatformController {
public class AdminPlatformController {
private final PlatformRepository platformRepository;
public PlatformController(PlatformRepository platformRepository) {
public AdminPlatformController(PlatformRepository platformRepository) {
this.platformRepository = platformRepository;
}

View File

@@ -0,0 +1,61 @@
package group.goforward.battlbuilder.controllers.utils;
import group.goforward.battlbuilder.ApiResponse;
import group.goforward.battlbuilder.dto.EmailRequestDto;
import group.goforward.battlbuilder.model.EmailRequest;
import group.goforward.battlbuilder.services.utils.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
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;
@RestController
@RequestMapping("/api/email")
public class EmailController {
private static final String EMAIL_STATUS_SENT = "SENT";
private final EmailService emailService;
@Autowired
public EmailController(EmailService emailService) {
this.emailService = emailService;
}
@PostMapping("/send")
public ResponseEntity<ApiResponse<EmailRequest>> sendEmail(@RequestBody EmailRequestDto emailDto) {
try {
EmailRequest emailRequest = emailService.sendEmail(
emailDto.getRecipient(),
emailDto.getSubject(),
emailDto.getBody()
);
return buildEmailResponse(emailRequest);
} catch (Exception e) {
return buildErrorResponse(e.getMessage());
}
}
private ResponseEntity<ApiResponse<EmailRequest>> buildEmailResponse(EmailRequest emailRequest) {
if (EMAIL_STATUS_SENT.equals(emailRequest.getStatus())) {
return ResponseEntity.ok(
ApiResponse.success(emailRequest, "Email sent successfully")
);
} else {
String errorMessage = "Failed to send email: " + emailRequest.getErrorMessage();
return ResponseEntity.status(500).body(
ApiResponse.error(errorMessage, emailRequest)
);
}
}
private ResponseEntity<ApiResponse<EmailRequest>> buildErrorResponse(String exceptionMessage) {
String errorMessage = "Error processing email request: " + exceptionMessage;
return ResponseEntity.status(500).body(
ApiResponse.error(errorMessage, null)
);
}
}

View File

@@ -0,0 +1,33 @@
package group.goforward.battlbuilder.dto;
// DTO for request
public class EmailRequestDto {
private String recipient;
private String subject;
private String body;
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}

View File

@@ -0,0 +1,107 @@
package group.goforward.battlbuilder.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "email_requests")
public class EmailRequest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String recipient;
@Column(nullable = false)
private String subject;
@Column(columnDefinition = "TEXT")
private String body;
@Column(name = "sent_at")
private LocalDateTime sentAt;
@Column(nullable = false)
private String status; // PENDING, SENT, FAILED
@Column(name = "error_message")
private String errorMessage;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
if (status == null) {
status = "PENDING";
}
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public LocalDateTime getSentAt() {
return sentAt;
}
public void setSentAt(LocalDateTime sentAt) {
this.sentAt = sentAt;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
}

View File

@@ -0,0 +1,12 @@
package group.goforward.battlbuilder.repos;
import group.goforward.battlbuilder.model.EmailRequest;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface EmailRequestRepository extends JpaRepository<EmailRequest, Long> {
List<EmailRequest> findByStatus(String status);
}

View File

@@ -0,0 +1,7 @@
package group.goforward.battlbuilder.services.utils;
import group.goforward.battlbuilder.model.EmailRequest;
public interface EmailService {
EmailRequest sendEmail(String recipient, String subject, String body);
}

View File

@@ -0,0 +1,60 @@
package group.goforward.battlbuilder.services.utils.impl;
import group.goforward.battlbuilder.model.EmailRequest;
import group.goforward.battlbuilder.repos.EmailRequestRepository;
import group.goforward.battlbuilder.services.utils.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private JavaMailSender mailSender;
@Autowired
private EmailRequestRepository emailRequestRepository;
@Value("${spring.mail.username}")
private String fromEmail;
@Transactional
public EmailRequest sendEmail(String recipient, String subject, String body) {
// Create and save email request
EmailRequest emailRequest = new EmailRequest();
emailRequest.setRecipient(recipient);
emailRequest.setSubject(subject);
emailRequest.setBody(body);
emailRequest.setStatus("PENDING");
emailRequest = emailRequestRepository.save(emailRequest);
try {
// Send email
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(fromEmail);
message.setTo(recipient);
message.setSubject(subject);
message.setText(body);
mailSender.send(message);
// Update status
emailRequest.setStatus("SENT");
emailRequest.setSentAt(LocalDateTime.now());
} catch (Exception e) {
// Update status with error
emailRequest.setStatus("FAILED");
emailRequest.setErrorMessage(e.getMessage());
}
return emailRequestRepository.save(emailRequest);
}
}

View File

@@ -24,3 +24,11 @@ spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
# SMTP Configuration
spring.mail.host=smtp.battl.builder
spring.mail.port=587
spring.mail.username=info@battl.builder
spring.mail.password=Cul8rman2025!
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

View File

@@ -3,7 +3,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Platform Manager</title>
<title>BattlBuilder Platform Manager</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {