diff --git a/pom.xml b/pom.xml
index ccbf697..4ff00b9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,14 +38,15 @@
- scm:git:https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
+ scm:git:https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
+
ssh://git@gitea.gofwd.group:2225/Forward_Group/ballistic-builder-spring.git
- 17
+ 21
${java.version}
${java.version}
@@ -63,6 +64,25 @@
-->
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+ runtime
+
org.springframework.boot
spring-boot-starter-web
@@ -155,8 +175,9 @@
maven-compiler-plugin
3.11.0
- ${maven.compiler.source}
- ${maven.compiler.target}
+ 21
+ 21
+ --enable-preview
diff --git a/sql/email_requests_schema.sql b/sql/email_requests_schema.sql
new file mode 100644
index 0000000..2fac6cf
--- /dev/null
+++ b/sql/email_requests_schema.sql
@@ -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);
diff --git a/src/main/java/group/goforward/battlbuilder/ApiResponse.java b/src/main/java/group/goforward/battlbuilder/ApiResponse.java
index d23af40..4efb1bf 100644
--- a/src/main/java/group/goforward/battlbuilder/ApiResponse.java
+++ b/src/main/java/group/goforward/battlbuilder/ApiResponse.java
@@ -24,12 +24,12 @@ public class ApiResponse {
this.timestamp = LocalDateTime.now();
}
- public static ApiResponse success(T data, String message) {
- String[] msg = {message};
- return new ApiResponse<>(API_SUCCESS, msg, data);
+ public static ApiResponse error(String message, T data) {
+ String[] msg = {message}; // ✅ Include the message
+ return new ApiResponse<>(API_ERROR, msg, data);
}
- public static ApiResponse success(T data) {
+ public static ApiResponse success(T data, String emailSentSuccessfully) {
String[] msg = {};
return new ApiResponse<>(API_SUCCESS, msg, data);
}
@@ -42,6 +42,7 @@ public class ApiResponse {
return new ApiResponse<>(API_ERROR, msg, null);
}
+
public String[] getMessages() {
return messages;
}
diff --git a/src/main/java/group/goforward/battlbuilder/configuration/PasswordConfig.java b/src/main/java/group/goforward/battlbuilder/configuration/PasswordConfig.java
index 1d7374a..7533c48 100644
--- a/src/main/java/group/goforward/battlbuilder/configuration/PasswordConfig.java
+++ b/src/main/java/group/goforward/battlbuilder/configuration/PasswordConfig.java
@@ -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();
-// }
-// }
\ No newline at end of file
+ return new BCryptPasswordEncoder();
+ }
+ }*/
diff --git a/src/main/java/group/goforward/battlbuilder/controllers/admin/PartCategoryAdminController.java b/src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPartCategoryController.java
similarity index 90%
rename from src/main/java/group/goforward/battlbuilder/controllers/admin/PartCategoryAdminController.java
rename to src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPartCategoryController.java
index 130b9c4..5ae1c30 100644
--- a/src/main/java/group/goforward/battlbuilder/controllers/admin/PartCategoryAdminController.java
+++ b/src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPartCategoryController.java
@@ -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;
}
diff --git a/src/main/java/group/goforward/battlbuilder/controllers/admin/PlatformController.java b/src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPlatformController.java
similarity index 91%
rename from src/main/java/group/goforward/battlbuilder/controllers/admin/PlatformController.java
rename to src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPlatformController.java
index 223ce93..307ef24 100644
--- a/src/main/java/group/goforward/battlbuilder/controllers/admin/PlatformController.java
+++ b/src/main/java/group/goforward/battlbuilder/controllers/admin/AdminPlatformController.java
@@ -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;
}
diff --git a/src/main/java/group/goforward/battlbuilder/controllers/utils/EmailController.java b/src/main/java/group/goforward/battlbuilder/controllers/utils/EmailController.java
new file mode 100644
index 0000000..56baedd
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/controllers/utils/EmailController.java
@@ -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> 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> 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> buildErrorResponse(String exceptionMessage) {
+ String errorMessage = "Error processing email request: " + exceptionMessage;
+ return ResponseEntity.status(500).body(
+ ApiResponse.error(errorMessage, null)
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/group/goforward/battlbuilder/dto/EmailRequestDto.java b/src/main/java/group/goforward/battlbuilder/dto/EmailRequestDto.java
new file mode 100644
index 0000000..4c375db
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/dto/EmailRequestDto.java
@@ -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;
+ }
+}
+
diff --git a/src/main/java/group/goforward/battlbuilder/model/EmailRequest.java b/src/main/java/group/goforward/battlbuilder/model/EmailRequest.java
new file mode 100644
index 0000000..8e785a7
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/model/EmailRequest.java
@@ -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;
+ }
+}
diff --git a/src/main/java/group/goforward/battlbuilder/repos/EmailRequestRepository.java b/src/main/java/group/goforward/battlbuilder/repos/EmailRequestRepository.java
new file mode 100644
index 0000000..4ec6b32
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/repos/EmailRequestRepository.java
@@ -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 {
+ List findByStatus(String status);
+}
diff --git a/src/main/java/group/goforward/battlbuilder/services/utils/EmailService.java b/src/main/java/group/goforward/battlbuilder/services/utils/EmailService.java
new file mode 100644
index 0000000..056acdb
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/services/utils/EmailService.java
@@ -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);
+}
diff --git a/src/main/java/group/goforward/battlbuilder/services/utils/impl/EmailServiceImpl.java b/src/main/java/group/goforward/battlbuilder/services/utils/impl/EmailServiceImpl.java
new file mode 100644
index 0000000..72388bc
--- /dev/null
+++ b/src/main/java/group/goforward/battlbuilder/services/utils/impl/EmailServiceImpl.java
@@ -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);
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index e91149f..cd0b324 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -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
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/platform-manager.jsp b/src/main/webapp/WEB-INF/views/platform-manager.jsp
index db90424..abb2a54 100644
--- a/src/main/webapp/WEB-INF/views/platform-manager.jsp
+++ b/src/main/webapp/WEB-INF/views/platform-manager.jsp
@@ -3,7 +3,7 @@
- Platform Manager
+ BattlBuilder Platform Manager