Skip to content

Commit 8e88fda

Browse files
LP-ReactGabriel Lopezletronx1984
authored
User authentication & attendee profile implementation + Flyway migrations (#12)
* Feature/profile attendee (#7) * chore(db): initialize flyway and base schema * feat(db): add audit base table * feat(db): add audit functions * feat(db): enable audit triggers * chore(db): rename flyway migration versions * fix(db): fix audit trigger migration * feat(auth): implement jwt authentication, registration and global error handling * feat: add AuditoriaContextFilter * chore: migrate database schema and backend to English * refactor(auth): replace emailVerified with verificationStatus and update register flow * feat(auth): support country code and generate E.164 phone on user registration * feat(db): add city_slug to cities with unique constraint per country * feat(auth): register and login using user identity and attendee profile * chore: AuthController in folder V1 * refactor(auth,user,attendee): move phone fields to attendee profile, remove profile image from users, align register request and validation * chore(config): harden application properties for stage environment * refactor(db): Add migration to remove old cities and insert Peruvian departments * feat(attendee): add update profile attendee (#9) * Fix/attendee patch response message (#10) * fix(profile_attendee): handle duplicate phone number error and update response format * refactor(db): unify ids to bigint * refactor(db): unify ids to bigint * refactor(attendee_profile): response update profile in controller * Feature/email verification (#11) * email-verification done * fix: ignore .env file and remove from tracking * fix: azure-mail-service structure * refactor: azure mail service only * refactor: properties * refactor: comments in properties * fix: all profiles properties --------- Co-authored-by: JuanCarlos <jcgpalacios1@gmail.com> * fix: azure key vault endpoint * fix: spacing in a migration * fix: environment variables --------- Co-authored-by: Gabriel Lopez <i202332157@cibertec.edu.pe> Co-authored-by: JuanCarlos <jcgpalacios1@gmail.com>
1 parent 406dcc9 commit 8e88fda

58 files changed

Lines changed: 2618 additions & 223 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ build/
3131

3232
### VS Code ###
3333
.vscode/
34+
35+
36+
.env

pom.xml

Lines changed: 101 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,66 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5-
<modelVersion>4.0.0</modelVersion>
6-
<parent>
7-
<groupId>org.springframework.boot</groupId>
8-
<artifactId>spring-boot-starter-parent</artifactId>
9-
<version>3.5.9</version>
10-
<relativePath /> <!-- lookup parent from repository -->
11-
</parent>
12-
<groupId>com.meevent</groupId>
13-
<artifactId>webapi</artifactId>
14-
<version>0.0.1-SNAPSHOT</version>
15-
<name>webapi</name>
16-
<description>Demo project for Spring Boot</description>
17-
<url />
18-
<licenses>
19-
<license />
20-
</licenses>
21-
<developers>
22-
<developer />
23-
</developers>
24-
<scm>
25-
<connection />
26-
<developerConnection />
27-
<tag />
28-
<url />
29-
</scm>
30-
<properties>
31-
<java.version>17</java.version>
32-
</properties>
33-
<dependencies>
34-
<dependency>
35-
<groupId>org.springframework.boot</groupId>
36-
<artifactId>spring-boot-starter</artifactId>
37-
</dependency>
38-
39-
<dependency>
40-
<groupId>org.springframework.boot</groupId>
41-
<artifactId>spring-boot-starter-test</artifactId>
42-
<scope>test</scope>
43-
</dependency>
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.springframework.boot</groupId>
8+
<artifactId>spring-boot-starter-parent</artifactId>
9+
<version>3.5.9</version>
10+
<relativePath /> <!-- lookup parent from repository -->
11+
</parent>
12+
<groupId>com.meevent</groupId>
13+
<artifactId>webapi</artifactId>
14+
<version>0.0.1-SNAPSHOT</version>
15+
<name>webapi</name>
16+
<description>Demo project for Spring Boot</description>
17+
<url />
18+
<licenses>
19+
<license />
20+
</licenses>
21+
<developers>
22+
<developer />
23+
</developers>
24+
<scm>
25+
<connection />
26+
<developerConnection />
27+
<tag />
28+
<url />
29+
</scm>
30+
<properties>
31+
<java.version>17</java.version>
32+
</properties>
33+
<dependencies>
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-starter</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.springframework.boot</groupId>
40+
<artifactId>spring-boot-starter-mail</artifactId>
41+
</dependency>
42+
<!-- Azure Dependency -->
43+
<dependency>
44+
<groupId>com.azure</groupId>
45+
<artifactId>azure-communication-email</artifactId>
46+
<version>1.0.0</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.springframework.boot</groupId>
50+
<artifactId>spring-boot-starter-security</artifactId>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>org.springframework.boot</groupId>
55+
<artifactId>spring-boot-starter-test</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>org.springframework.security</groupId>
61+
<artifactId>spring-security-test</artifactId>
62+
<scope>test</scope>
63+
</dependency>
4464

4565
<dependency>
4666
<groupId>org.postgresql</groupId>
@@ -74,16 +94,47 @@
7494
<groupId>org.springframework.boot</groupId>
7595
<artifactId>spring-boot-starter-validation</artifactId>
7696
</dependency>
77-
</dependencies>
97+
98+
<dependency>
99+
<groupId>org.flywaydb</groupId>
100+
<artifactId>flyway-core</artifactId>
101+
</dependency>
102+
103+
<dependency>
104+
<groupId>org.flywaydb</groupId>
105+
<artifactId>flyway-database-postgresql</artifactId>
106+
</dependency>
107+
108+
<dependency>
109+
<groupId>io.jsonwebtoken</groupId>
110+
<artifactId>jjwt-api</artifactId>
111+
<version>0.12.6</version>
112+
</dependency>
113+
114+
<dependency>
115+
<groupId>io.jsonwebtoken</groupId>
116+
<artifactId>jjwt-impl</artifactId>
117+
<version>0.12.6</version>
118+
<scope>runtime</scope>
119+
</dependency>
120+
121+
<dependency>
122+
<groupId>io.jsonwebtoken</groupId>
123+
<artifactId>jjwt-jackson</artifactId>
124+
<version>0.12.6</version>
125+
<scope>runtime</scope>
126+
</dependency>
127+
128+
</dependencies>
78129

79130

80-
<build>
81-
<plugins>
82-
<plugin>
83-
<groupId>org.springframework.boot</groupId>
84-
<artifactId>spring-boot-maven-plugin</artifactId>
85-
</plugin>
86-
</plugins>
87-
</build>
131+
<build>
132+
<plugins>
133+
<plugin>
134+
<groupId>org.springframework.boot</groupId>
135+
<artifactId>spring-boot-maven-plugin</artifactId>
136+
</plugin>
137+
</plugins>
138+
</build>
88139

89140
</project>

src/main/java/com/meevent/webapi/Controller/ProductController.java

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.meevent.webapi.Controller.v1;
2+
3+
import com.meevent.webapi.dto.request.UpdateAttendeeProfileRequest;
4+
import com.meevent.webapi.dto.response.AttendeeProfileResponse;
5+
import com.meevent.webapi.dto.response.MessageResponse;
6+
import com.meevent.webapi.service.AttendeeService;
7+
import jakarta.validation.Valid;
8+
import lombok.RequiredArgsConstructor;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.core.context.SecurityContextHolder;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@RestController
16+
@RequestMapping("/api/v1/attendees")
17+
@RequiredArgsConstructor
18+
public class AttendeeController {
19+
private final AttendeeService attendeeService;
20+
21+
@PatchMapping("/profile")
22+
public ResponseEntity<MessageResponse> updateMyProfile( @Valid @RequestBody UpdateAttendeeProfileRequest request) {
23+
String userEmail = SecurityContextHolder.getContext().getAuthentication().getName();
24+
attendeeService.updateProfile(userEmail, request);
25+
26+
return ResponseEntity.ok(new MessageResponse("Perfil actualizado correctamente"));
27+
}
28+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.meevent.webapi.Controller.v1;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.PostMapping;
6+
import org.springframework.web.bind.annotation.RequestBody;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RequestParam;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import com.meevent.webapi.dto.request.LoginRequest;
12+
import com.meevent.webapi.dto.request.RegisterRequest;
13+
import com.meevent.webapi.dto.response.AuthResponse;
14+
import com.meevent.webapi.service.AuthService;
15+
16+
import jakarta.validation.Valid;
17+
import lombok.RequiredArgsConstructor;
18+
19+
@RestController
20+
@RequestMapping("/api/v1/auth")
21+
@RequiredArgsConstructor
22+
public class AuthController {
23+
24+
private final AuthService _authService;
25+
26+
@PostMapping("/login")
27+
public ResponseEntity<AuthResponse> login(@Valid @RequestBody LoginRequest request) {
28+
return ResponseEntity.ok(_authService.login(request));
29+
}
30+
31+
@PostMapping("/register")
32+
public ResponseEntity<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
33+
AuthResponse response = _authService.register(request);
34+
return ResponseEntity.status(HttpStatus.CREATED).body(response);
35+
}
36+
37+
38+
//---new endpoint
39+
@PostMapping("/verify-email")
40+
public ResponseEntity<String> verifyEmail(@RequestParam String token) {
41+
_authService.verifyEmail(token);
42+
return ResponseEntity.ok("Cuenta verificada exitosamente");
43+
}
44+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.meevent.webapi.dto.request;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import jakarta.validation.constraints.Email;
5+
import jakarta.validation.constraints.NotBlank;
6+
7+
public record LoginRequest(
8+
@NotBlank(message = "Email is required")
9+
@Email(message = "Invalid email format")
10+
@JsonProperty("email")
11+
String email,
12+
13+
@NotBlank(message = "Password is required")
14+
@JsonProperty("password")
15+
String password
16+
17+
) {}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.meevent.webapi.dto.request;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import jakarta.validation.constraints.*;
5+
6+
import java.time.LocalDate;
7+
8+
public record RegisterRequest(
9+
/* ========== Attendee Profile ========== */
10+
@NotBlank(message = "Full name is required")
11+
@Size(min = 3, max = 150)
12+
@JsonProperty("full_name")
13+
String fullName,
14+
15+
@Past(message = "Birth date must be in the past")
16+
@JsonProperty("birth_date")
17+
LocalDate birthDate,
18+
19+
@NotNull(message = "City is required")
20+
@JsonProperty("city_id")
21+
Long cityId,
22+
23+
/* ========== User Identity ========== */
24+
@NotBlank(message = "Email is required")
25+
@Email
26+
@Size(max = 150)
27+
@JsonProperty("email")
28+
String email,
29+
30+
@NotBlank(message = "Password is required")
31+
@Size(min = 8, message = "Password must be at least 8 characters long")
32+
@Pattern(
33+
regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$",
34+
message = "Password must contain uppercase, lowercase, number and special character"
35+
)
36+
@JsonProperty("password")
37+
String password,
38+
39+
@Pattern(
40+
regexp = "^\\+[1-9][0-9]{0,3}$",
41+
message = "Invalid country code format"
42+
)
43+
@JsonProperty("country_code")
44+
String countryCode,
45+
46+
@Pattern(
47+
regexp = "^[0-9]{9,20}$",
48+
message = "Phone number must contain only digits"
49+
)
50+
@JsonProperty("phone_number")
51+
String phoneNumber
52+
) {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.meevent.webapi.dto.request;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import jakarta.validation.constraints.Pattern;
5+
import jakarta.validation.constraints.Size;
6+
7+
import java.time.LocalDate;
8+
9+
public record UpdateAttendeeProfileRequest(
10+
@Size(min = 3, max = 150)
11+
@JsonProperty("full_name")
12+
String fullName,
13+
14+
@JsonProperty("city_id")
15+
Long cityId,
16+
17+
@JsonProperty("birth_date")
18+
LocalDate birthDate,
19+
20+
@Pattern(
21+
regexp = "^\\+[1-9][0-9]{0,3}$",
22+
message = "Invalid country code format"
23+
)
24+
@JsonProperty("country_code")
25+
String countryCode,
26+
27+
@Pattern(
28+
regexp = "^[0-9]{9,20}$",
29+
message = "Phone number must contain only digits"
30+
)
31+
@JsonProperty("phone_number")
32+
String phoneNumber
33+
34+
) {}

0 commit comments

Comments
 (0)