Skip to content

Commit f3105f8

Browse files
NotNull added at subject filed at backend
Basic Auth added at Java class level Signed-off-by: vimal-java-dev <vimal929@gmail.com>
1 parent c94e398 commit f3105f8

13 files changed

Lines changed: 364 additions & 153 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ logs/
2424
# Environment / Secrets
2525
############################################
2626
.env.dev
27+
.env.prod
2728
.env.*
2829
*.env
2930
*.key

pom.xml

Lines changed: 125 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,135 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4-
<modelVersion>4.0.0</modelVersion>
5-
<parent>
6-
<groupId>org.springframework.boot</groupId>
7-
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.4.10</version>
9-
<relativePath/> <!-- lookup parent from repository -->
10-
</parent>
11-
<groupId>com.vimaltech</groupId>
12-
<artifactId>contact-api</artifactId>
13-
<version>0.0.1-SNAPSHOT</version>
14-
<name>contact-api</name>
15-
<description>VimalTech Contact API - Spring Boot backend service for portfolio inquiries</description>
16-
<url/>
17-
<licenses>
18-
<license/>
19-
</licenses>
20-
<developers>
21-
<developer/>
22-
</developers>
23-
<scm>
24-
<connection/>
25-
<developerConnection/>
26-
<tag/>
27-
<url/>
28-
</scm>
29-
<properties>
30-
<java.version>21</java.version>
31-
</properties>
32-
<dependencies>
33-
<dependency>
34-
<groupId>org.springframework.boot</groupId>
35-
<artifactId>spring-boot-starter-data-jpa</artifactId>
36-
</dependency>
37-
<dependency>
38-
<groupId>org.springframework.boot</groupId>
39-
<artifactId>spring-boot-starter-mail</artifactId>
40-
</dependency>
41-
<dependency>
42-
<groupId>org.springframework.boot</groupId>
43-
<artifactId>spring-boot-starter-validation</artifactId>
44-
</dependency>
45-
<dependency>
46-
<groupId>org.springframework.boot</groupId>
47-
<artifactId>spring-boot-starter-web</artifactId>
48-
</dependency>
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>3.4.10</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.vimaltech</groupId>
12+
<artifactId>contact-api</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>contact-api</name>
15+
<description>VimalTech Contact API - Spring Boot backend service for portfolio inquiries</description>
16+
<url/>
17+
<licenses>
18+
<license/>
19+
</licenses>
20+
<developers>
21+
<developer/>
22+
</developers>
23+
<scm>
24+
<connection/>
25+
<developerConnection/>
26+
<tag/>
27+
<url/>
28+
</scm>
29+
<properties>
30+
<java.version>21</java.version>
31+
</properties>
32+
<dependencies>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-starter-data-jpa</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-starter-mail</artifactId>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-starter-validation</artifactId>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-starter-web</artifactId>
48+
</dependency>
4949

50-
<dependency>
51-
<groupId>com.h2database</groupId>
52-
<artifactId>h2</artifactId>
53-
<scope>test</scope>
54-
</dependency>
55-
<dependency>
56-
<groupId>org.postgresql</groupId>
57-
<artifactId>postgresql</artifactId>
58-
<scope>runtime</scope>
59-
</dependency>
60-
<dependency>
61-
<groupId>com.mysql</groupId>
62-
<artifactId>mysql-connector-j</artifactId>
63-
<scope>runtime</scope>
64-
</dependency>
65-
<dependency>
66-
<groupId>org.projectlombok</groupId>
67-
<artifactId>lombok</artifactId>
68-
<version>1.18.30</version>
69-
<optional>true</optional>
70-
</dependency>
71-
<dependency>
72-
<groupId>org.springframework.boot</groupId>
73-
<artifactId>spring-boot-starter-test</artifactId>
74-
<scope>test</scope>
75-
</dependency>
76-
<dependency>
77-
<groupId>org.apache.commons</groupId>
78-
<artifactId>commons-lang3</artifactId>
79-
<version>3.18.0</version>
80-
</dependency>
81-
<dependency>
82-
<groupId>org.springdoc</groupId>
83-
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
84-
<version>2.7.0</version>
85-
</dependency>
86-
<dependency>
87-
<groupId>org.flywaydb</groupId>
88-
<artifactId>flyway-core</artifactId>
89-
</dependency>
50+
<dependency>
51+
<groupId>com.h2database</groupId>
52+
<artifactId>h2</artifactId>
53+
<scope>test</scope>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.postgresql</groupId>
57+
<artifactId>postgresql</artifactId>
58+
<scope>runtime</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.mysql</groupId>
62+
<artifactId>mysql-connector-j</artifactId>
63+
<scope>runtime</scope>
64+
</dependency>
65+
<dependency>
66+
<groupId>org.projectlombok</groupId>
67+
<artifactId>lombok</artifactId>
68+
<version>1.18.30</version>
69+
<optional>true</optional>
70+
</dependency>
71+
<dependency>
72+
<groupId>org.springframework.boot</groupId>
73+
<artifactId>spring-boot-starter-test</artifactId>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>org.apache.commons</groupId>
78+
<artifactId>commons-lang3</artifactId>
79+
<version>3.18.0</version>
80+
</dependency>
81+
<dependency>
82+
<groupId>org.springdoc</groupId>
83+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
84+
<version>2.7.0</version>
85+
</dependency>
86+
<dependency>
87+
<groupId>org.flywaydb</groupId>
88+
<artifactId>flyway-core</artifactId>
89+
</dependency>
9090

91-
<dependency>
92-
<groupId>org.flywaydb</groupId>
93-
<artifactId>flyway-database-postgresql</artifactId>
94-
</dependency>
91+
<dependency>
92+
<groupId>org.flywaydb</groupId>
93+
<artifactId>flyway-database-postgresql</artifactId>
94+
</dependency>
9595

96-
<dependency>
97-
<groupId>com.bucket4j</groupId>
98-
<artifactId>bucket4j-core</artifactId>
99-
<version>8.9.0</version>
100-
</dependency>
96+
<dependency>
97+
<groupId>com.bucket4j</groupId>
98+
<artifactId>bucket4j-core</artifactId>
99+
<version>8.9.0</version>
100+
</dependency>
101101

102-
<dependency>
103-
<groupId>org.springframework.boot</groupId>
104-
<artifactId>spring-boot-starter-actuator</artifactId>
105-
</dependency>
102+
<dependency>
103+
<groupId>org.springframework.boot</groupId>
104+
<artifactId>spring-boot-starter-actuator</artifactId>
105+
</dependency>
106106

107-
<dependency>
108-
<groupId>io.micrometer</groupId>
109-
<artifactId>micrometer-registry-prometheus</artifactId>
110-
</dependency>
111-
</dependencies>
107+
<dependency>
108+
<groupId>org.springframework.boot</groupId>
109+
<artifactId>spring-boot-starter-security</artifactId>
110+
</dependency>
112111

113-
<build>
114-
<plugins>
115-
<plugin>
116-
<groupId>org.springframework.boot</groupId>
117-
<artifactId>spring-boot-maven-plugin</artifactId>
118-
<configuration>
119-
<excludes>
120-
<exclude>
121-
<groupId>org.projectlombok</groupId>
122-
<artifactId>lombok</artifactId>
123-
</exclude>
124-
</excludes>
125-
</configuration>
126-
</plugin>
127-
</plugins>
128-
</build>
112+
<dependency>
113+
<groupId>io.micrometer</groupId>
114+
<artifactId>micrometer-registry-prometheus</artifactId>
115+
</dependency>
116+
</dependencies>
117+
118+
<build>
119+
<plugins>
120+
<plugin>
121+
<groupId>org.springframework.boot</groupId>
122+
<artifactId>spring-boot-maven-plugin</artifactId>
123+
<configuration>
124+
<excludes>
125+
<exclude>
126+
<groupId>org.projectlombok</groupId>
127+
<artifactId>lombok</artifactId>
128+
</exclude>
129+
</excludes>
130+
</configuration>
131+
</plugin>
132+
</plugins>
133+
</build>
129134

130135
</project>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.vimaltech.contactapi.config;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.http.HttpMethod;
6+
import org.springframework.security.config.Customizer;
7+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8+
import org.springframework.security.core.userdetails.User;
9+
import org.springframework.security.core.userdetails.UserDetails;
10+
import org.springframework.security.core.userdetails.UserDetailsService;
11+
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
12+
import org.springframework.security.web.SecurityFilterChain;
13+
14+
@Configuration
15+
public class SecurityConfig {
16+
17+
@Bean
18+
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
19+
20+
http
21+
.csrf(csrf -> csrf.disable()) // API use-case
22+
.authorizeHttpRequests(auth -> auth
23+
24+
// ✅ Public endpoints
25+
.requestMatchers(HttpMethod.POST, "/api/v1/contacts").permitAll()
26+
.requestMatchers(HttpMethod.GET, "/api/v1/contacts/options").permitAll()
27+
28+
// 🔒 Admin endpoint
29+
.requestMatchers(HttpMethod.GET, "/api/v1/contacts").authenticated()
30+
31+
// Everything else
32+
.anyRequest().permitAll()
33+
)
34+
// ✅ NEW WAY (Spring Security 6+)
35+
.httpBasic(Customizer.withDefaults());
36+
37+
return http.build();
38+
}
39+
40+
@Bean
41+
public UserDetailsService userDetailsService() {
42+
String password = System.getenv("ADMIN_PASSWORD");
43+
44+
UserDetails user = User
45+
.withUsername("admin")
46+
.password("{noop}" + password)
47+
.roles("ADMIN")
48+
.build();
49+
50+
return new InMemoryUserDetailsManager(user);
51+
}
52+
}

src/main/java/com/vimaltech/contactapi/controller/ContactController.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.vimaltech.contactapi.dto.ApiResponse;
44
import com.vimaltech.contactapi.dto.ContactRequest;
5+
import com.vimaltech.contactapi.dto.InquiryOption;
56
import com.vimaltech.contactapi.service.ContactService;
67
import jakarta.validation.Valid;
78
import lombok.RequiredArgsConstructor;
@@ -10,6 +11,7 @@
1011
import org.springframework.web.bind.annotation.*;
1112

1213
import java.time.LocalDateTime;
14+
import java.util.List;
1315

1416
@RestController
1517
@RequestMapping("/api/v1/contacts")
@@ -18,6 +20,7 @@ public class ContactController {
1820

1921
private final ContactService contactService;
2022

23+
// ✅ POST contact
2124
@PostMapping
2225
public ResponseEntity<ApiResponse> submitContact(
2326
@Valid @RequestBody ContactRequest request) {
@@ -33,8 +36,15 @@ public ResponseEntity<ApiResponse> submitContact(
3336
return ResponseEntity.status(HttpStatus.CREATED).body(response);
3437
}
3538

39+
// ✅ GET all contacts (admin use)
3640
@GetMapping
37-
public ResponseEntity<?> getAllContacts() {
41+
public ResponseEntity<?> getAllContactsForAdmin() {
3842
return ResponseEntity.ok(contactService.getAllContacts());
3943
}
44+
45+
// ✅ NEW: GET dropdown options (frontend use)
46+
@GetMapping("/options")
47+
public ResponseEntity<List<InquiryOption>> getInquiryOptions() {
48+
return ResponseEntity.ok(contactService.getInquiryOptions());
49+
}
4050
}

src/main/java/com/vimaltech/contactapi/dto/ContactRequest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.vimaltech.contactapi.dto;
22

3+
import com.vimaltech.contactapi.enums.InquiryType;
34
import jakarta.validation.constraints.Email;
45
import jakarta.validation.constraints.NotBlank;
6+
import jakarta.validation.constraints.NotNull;
57
import jakarta.validation.constraints.Size;
68

79
public record ContactRequest(
@@ -13,8 +15,8 @@ public record ContactRequest(
1315
@NotBlank(message = "Email is required")
1416
String email,
1517

16-
@Size(max = 255, message = "Subject cannot exceed 255 characters")
17-
String subject,
18+
@NotNull(message = "Subject is required")
19+
InquiryType subject,
1820

1921
@NotBlank(message = "Message is required")
2022
@Size(min = 10, max = 1000,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.vimaltech.contactapi.dto;
2+
3+
public record InquiryOption(
4+
String value,
5+
String label
6+
) {
7+
}

0 commit comments

Comments
 (0)