From 78167800970c16559578b624d1675a75cb646ef8 Mon Sep 17 00:00:00 2001 From: aguizzo Date: Wed, 5 Feb 2025 11:44:54 +0100 Subject: [PATCH 1/6] feat: added setup for local database and for testing database fix: deleted a duplicated dependency in pom.xml --- backend/pronunciationAppBack/pom.xml | 5 ----- .../src/main/resources/application.properties | 6 +++--- .../src/test/resources/application.properties | 8 ++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 backend/pronunciationAppBack/src/test/resources/application.properties diff --git a/backend/pronunciationAppBack/pom.xml b/backend/pronunciationAppBack/pom.xml index 68220ba2e..3759b7341 100644 --- a/backend/pronunciationAppBack/pom.xml +++ b/backend/pronunciationAppBack/pom.xml @@ -60,11 +60,6 @@ postgresql runtime - - org.projectlombok - lombok - true - org.springframework.boot spring-boot-starter-test diff --git a/backend/pronunciationAppBack/src/main/resources/application.properties b/backend/pronunciationAppBack/src/main/resources/application.properties index 83cb16f3e..44860e451 100644 --- a/backend/pronunciationAppBack/src/main/resources/application.properties +++ b/backend/pronunciationAppBack/src/main/resources/application.properties @@ -12,9 +12,9 @@ spring.h2.console.enabled=true # H2 LOCAL DB SERVER -spring.datasource.url=jdbc:h2:/home/albert/MyProjects/DataBase/pronunciationDB/pronunciationDB.db -spring.datasource.username=albert -spring.datasource.password=1234 +spring.datasource.url=jdbc:h2:/home/aguizzo/Databases +spring.datasource.username=admin +spring.datasource.password=admin # DDL OPTIONS: create-drop, create, update, none, validate spring.jpa.hibernate.ddl-auto=none \ No newline at end of file diff --git a/backend/pronunciationAppBack/src/test/resources/application.properties b/backend/pronunciationAppBack/src/test/resources/application.properties new file mode 100644 index 000000000..b49d63df4 --- /dev/null +++ b/backend/pronunciationAppBack/src/test/resources/application.properties @@ -0,0 +1,8 @@ +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true \ No newline at end of file From 3850da19e25d369c362d8dc24a8d243e4791cd74 Mon Sep 17 00:00:00 2001 From: aguizzo Date: Wed, 5 Feb 2025 12:50:06 +0100 Subject: [PATCH 2/6] feat: created @Entity User --- .../dev/pronunciationAppBack/model/User.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java new file mode 100644 index 000000000..fbd24c084 --- /dev/null +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java @@ -0,0 +1,38 @@ +package dev.pronunciationAppBack.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; + +@Entity +@Getter @Setter @NoArgsConstructor +public class User { + + @Id + private String id; + private String name; + private String email; + private int age; + + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate joinDate; + + public User(String id, String name, String email, int age, LocalDate joinDate) { + this.id = id; + this.name = name; + this.email = email; + this.age = age; + this.joinDate = joinDate != null ? joinDate : LocalDate.now(); + } + + @Override + public String toString() { + return String.format("User{id='%s', name='%s', email='%s', age=%d, joinDate=%s}", + id, name, email, age, joinDate); + } +} From 5abe695575931820f7829046ab0e64ac336018a9 Mon Sep 17 00:00:00 2001 From: aguizzo Date: Wed, 5 Feb 2025 16:46:42 +0100 Subject: [PATCH 3/6] feat: added validation to AppUser @Entity --- backend/pronunciationAppBack/pom.xml | 6 ++++++ .../model/{User.java => AppUser.java} | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) rename backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/{User.java => AppUser.java} (53%) diff --git a/backend/pronunciationAppBack/pom.xml b/backend/pronunciationAppBack/pom.xml index 3759b7341..0c420b7eb 100644 --- a/backend/pronunciationAppBack/pom.xml +++ b/backend/pronunciationAppBack/pom.xml @@ -39,6 +39,12 @@ lombok true + + org.springframework.boot + spring-boot-starter-validation + 3.3.7 + + org.springframework.boot spring-boot-starter-web diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/AppUser.java similarity index 53% rename from backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java rename to backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/AppUser.java index fbd24c084..1946720b4 100644 --- a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/User.java +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/model/AppUser.java @@ -2,6 +2,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.validation.constraints.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,21 +12,35 @@ @Entity @Getter @Setter @NoArgsConstructor -public class User { +public class AppUser { @Id private String id; + + @NotBlank(message = "Name should not be empty") + @Size(min = 3, max=40, message = "Name should be between 3 and 40 characters") private String name; + + @NotBlank(message = "Email should not be empty") + @Email(message = "Please enter a valid email address") private String email; + + @NotBlank(message = "Password should not be empty") + @Size(min = 6, max=20, message = "Password should be between 6 and 20 characters") + private String password; + + @Min(value = 3, message = "Age should be between 3 and 100") + @Max(value = 100, message = "Age should be between 3 and 100") private int age; @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate joinDate; - public User(String id, String name, String email, int age, LocalDate joinDate) { + public AppUser(String id, String name, String email, String password, int age, LocalDate joinDate) { this.id = id; this.name = name; this.email = email; + this.password = password; this.age = age; this.joinDate = joinDate != null ? joinDate : LocalDate.now(); } From 8a9c71455a696cdcfeef2ef8181f4f68e4ef112a Mon Sep 17 00:00:00 2001 From: aguizzo Date: Wed, 5 Feb 2025 20:47:22 +0100 Subject: [PATCH 4/6] feat: added @Controller, @Service and @Repository for AppUser --- .../controller/AppUserController.java | 82 +++++++++++++++++++ .../repository/AppUserRepository.java | 12 +++ .../service/AppUserService.java | 62 ++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java create mode 100644 backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/repository/AppUserRepository.java create mode 100644 backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/service/AppUserService.java diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java new file mode 100644 index 000000000..a669d989c --- /dev/null +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java @@ -0,0 +1,82 @@ +package dev.pronunciationAppBack.controller; + +import dev.pronunciationAppBack.model.AppUser; +import dev.pronunciationAppBack.service.AppUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +@RestController +@RequestMapping("/api/users") +public class AppUserController { + + @Autowired + private AppUserService appUserService; + + @GetMapping + public ResponseEntity> getAllUsers() { + List users = appUserService.getAllUsers(); + HttpHeaders headers = getCommonHeaders("Get all users"); + + return !users.isEmpty() + ? new ResponseEntity<>(users, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @GetMapping("/{id}") + public ResponseEntity getUserById(@PathVariable String id) { + Optional user = appUserService.findAppUserById(id); + HttpHeaders headers = getCommonHeaders("Get user by ID"); + + return user.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK)) + .orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND)); + } + + @PostMapping("/createUser") + public ResponseEntity createUser(@RequestBody AppUser user) { + Optional createdUser = appUserService.createAppUser(user); + HttpHeaders headers = getCommonHeaders("Create a new user"); + + return createdUser.map(value -> new ResponseEntity<>(value, headers, HttpStatus.CREATED)) + .orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST)); + } + + @PutMapping("/{id}") + public ResponseEntity updateUser(@PathVariable String id, @RequestBody AppUser user) { + Optional updatedUser = appUserService.updateAppUser(user); + HttpHeaders headers = getCommonHeaders("Update a user"); + + return updatedUser.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK)) + .orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND)); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@PathVariable String id) { + HttpHeaders headers = getCommonHeaders("Delete a user"); + + return appUserService.deleteAppUser(id) + ? new ResponseEntity<>("User deleted", headers, HttpStatus.OK) + : new ResponseEntity<>("User not found", headers, HttpStatus.NOT_FOUND); + + } + + //TODO: get appUser by email using request param + + private HttpHeaders getCommonHeaders(String description) { + HttpHeaders headers = new HttpHeaders(); + headers.add("desc", description); + headers.add("content-type", "application/json"); + headers.add("date", new Date().toString()); + headers.add("server", "Spring Boot"); + headers.add("version", "1.0.0"); + headers.add("word-count", String.valueOf(appUserService.getAppUserCount())); + headers.add("object", "appUsers"); + return headers; + } +} diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/repository/AppUserRepository.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/repository/AppUserRepository.java new file mode 100644 index 000000000..3b35c4451 --- /dev/null +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/repository/AppUserRepository.java @@ -0,0 +1,12 @@ +package dev.pronunciationAppBack.repository; + +import dev.pronunciationAppBack.model.AppUser; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + + +public interface AppUserRepository extends JpaRepository { + Optional findByEmail(String email); +} + diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/service/AppUserService.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/service/AppUserService.java new file mode 100644 index 000000000..9272c9969 --- /dev/null +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/service/AppUserService.java @@ -0,0 +1,62 @@ +package dev.pronunciationAppBack.service; + +import dev.pronunciationAppBack.model.AppUser; +import dev.pronunciationAppBack.repository.AppUserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class AppUserService { + + @Autowired + private AppUserRepository appUserRepository; + + public List getAllUsers() { + return appUserRepository.findAll(); + } + + public Optional findAppUserById(String id) { + return appUserRepository.findById(id); + } + + public Optional createAppUser(AppUser appUser) { + return Optional.of(appUserRepository.save(appUser)); + } + + public Optional updateAppUser(AppUser appUserDetails) { + Optional existingUser = findAppUserById(appUserDetails.getId()); + + if (existingUser.isPresent()) { + AppUser updatedUser = existingUser.get(); + updatedUser.setName(appUserDetails.getName()); + updatedUser.setEmail(appUserDetails.getEmail()); + updatedUser.setPassword(appUserDetails.getPassword()); + return Optional.of(appUserRepository.save(updatedUser)); + } + return Optional.empty(); + + } + + public boolean deleteAppUser(String id) { + appUserRepository.deleteById(id); + Optional deletedUser = appUserRepository.findById(id); + return deletedUser.isEmpty(); + } + + public Optional findAppUserByEmail(String email) { + return appUserRepository.findByEmail(email); + } + + public boolean deleteAllAppUsers() { + appUserRepository.deleteAll(); + return getAppUserCount() == 0; + } + + public long getAppUserCount() { + return appUserRepository.count(); + } + +} From 503aaf40b69836d9822f40bea10f11c6d4618c6d Mon Sep 17 00:00:00 2001 From: aguizzo Date: Wed, 5 Feb 2025 23:33:45 +0100 Subject: [PATCH 5/6] fix: edited create user endpoint --- .../dev/pronunciationAppBack/controller/AppUserController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java index a669d989c..7af775b92 100644 --- a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java @@ -38,7 +38,7 @@ public ResponseEntity getUserById(@PathVariable String id) { .orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND)); } - @PostMapping("/createUser") + @PostMapping() public ResponseEntity createUser(@RequestBody AppUser user) { Optional createdUser = appUserService.createAppUser(user); HttpHeaders headers = getCommonHeaders("Create a new user"); From 679a4fbf596a328c89c1151ae0fda6d642b86cf9 Mon Sep 17 00:00:00 2001 From: aguizzo Date: Thu, 6 Feb 2025 10:16:55 +0100 Subject: [PATCH 6/6] feat: added enpoint for searching AppUser by email --- .../controller/AppUserController.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java index 7af775b92..ed6878041 100644 --- a/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java +++ b/backend/pronunciationAppBack/src/main/java/dev/pronunciationAppBack/controller/AppUserController.java @@ -66,7 +66,14 @@ public ResponseEntity deleteUser(@PathVariable String id) { } - //TODO: get appUser by email using request param + @GetMapping("/findBy") + public ResponseEntity getAppUserByEmail(@RequestParam String email) { + Optional user = appUserService.findAppUserByEmail(email); + HttpHeaders headers = getCommonHeaders("Get user by email"); + + return user.map(value -> new ResponseEntity<>(value, headers, HttpStatus.OK)) + .orElseGet(() -> new ResponseEntity<>(headers, HttpStatus.NOT_FOUND)); + } private HttpHeaders getCommonHeaders(String description) { HttpHeaders headers = new HttpHeaders(); @@ -75,7 +82,7 @@ private HttpHeaders getCommonHeaders(String description) { headers.add("date", new Date().toString()); headers.add("server", "Spring Boot"); headers.add("version", "1.0.0"); - headers.add("word-count", String.valueOf(appUserService.getAppUserCount())); + headers.add("user-count", String.valueOf(appUserService.getAppUserCount())); headers.add("object", "appUsers"); return headers; }