Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -80,4 +81,11 @@ public ResponseEntity<ImageDTO> addUserImage(@PathVariable long id, @RequestPara
return ResponseEntity.created(location).body(new ImageDTO(image.getId()));
}

@DeleteMapping("/{id}")
public void deleteUser(@PathVariable long id) {

usersService.deleteUser(id);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.GET, "/api/v1/users/**").hasRole("REGISTERED_USER")
.requestMatchers(HttpMethod.DELETE, "/api/v1/users/**").hasRole("REGISTERED_USER")
.anyRequest().permitAll());

http.formLogin(formLogin -> formLogin.disable());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ public Image addUserImage(long id, MultipartFile imageFile) throws IOException {
return userRepository.save(user).getImage();
}

@PreAuthorize("hasRole('ADMIN') or principal.username == #id.toString()")
public void deleteUser(long id) {

Optional<User> user = userRepository.findById(id);

if (user.isPresent()) {

userRepository.deleteById(id);

}

}

public UserDTO toDTO(User user) {
return userMapper.toDTO(user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,121 @@ public void postImageWithInvalidFile() {
.body("message", equalTo("El tipo de archivo no es válido. Solo se permiten imágenes JPEG, PNG y WebP."));
}

@Test
public void deleteUserAsNotLoggedIn() {

given()
.when().delete("users/1")
.then().statusCode(401).contentType(ContentType.JSON)
.body("status", equalTo(401))
.body("error", equalTo("Unauthorized"));
}

@Test
public void deleteOwnUser() {
String authToken = given()
.header("Content-Type", "application/json")
.body("""
{
"username": "user@example.com",
"password": "userpass"
}
""")
.when().post("auth/login")
.then().statusCode(200).contentType(ContentType.JSON)
.extract().cookie("AuthToken");

given()
.header("Content-Type", "application/json")
.cookie("AuthToken", authToken)
.when().delete("users/1")
.then().statusCode(200);

given()
.header("Content-Type", "application/json")
.body("""
{
"username": "user@example.com",
"password": "userpass"
}
""")
.when().post("auth/login")
.then().statusCode(401).contentType(ContentType.JSON)
.body("error", equalTo("Unauthorized"));
}

@Test
public void deleteOtherUserAsNoAdmin() {
String authToken = given()
.header("Content-Type", "application/json")
.body("""
{
"username": "user@example.com",
"password": "userpass"
}
""")
.when().post("auth/login")
.then().statusCode(200).contentType(ContentType.JSON)
.extract().cookie("AuthToken");

given()
.header("Content-Type", "application/json")
.cookie("AuthToken", authToken)
.when().delete("users/2")
.then().statusCode(403).contentType(ContentType.JSON)
.body("error", equalTo("Forbidden"));
}

@Test
public void deleteUsersAsAdmin() {
String authToken = given()
.header("Content-Type", "application/json")
.body("""
{
"username": "admin@example.com",
"password": "adminpass"
}
""")
.when().post("auth/login")
.then().statusCode(200).contentType(ContentType.JSON)
.extract().cookie("AuthToken");

given()
.header("Content-Type", "application/json")
.cookie("AuthToken", authToken)
.when().delete("users/1")
.then().statusCode(200);

given()
.header("Content-Type", "application/json")
.cookie("AuthToken", authToken)
.when().delete("users/2")
.then().statusCode(200);

given()
.header("Content-Type", "application/json")
.body("""
{
"username": "user@example.com",
"password": "userpass"
}
""")
.when().post("auth/login")
.then().statusCode(401).contentType(ContentType.JSON)
.body("error", equalTo("Unauthorized"));

given()
.header("Content-Type", "application/json")
.body("""
{
"username": "admin@example.com",
"password": "adminpass"
}
""")
.when().post("auth/login")
.then().statusCode(401).contentType(ContentType.JSON)
.body("error", equalTo("Unauthorized"));

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public void loginWrongCredentialsTest(String testName, String email, String pass

wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("error-message")));
assertThat(driver.findElement(By.id("error-message")).getText())
.isEqualTo("Error al iniciar sesión. Por favor, inténtenlo de nuevo");
.isEqualTo("Error al iniciar sesión. Por favor, inténtelo de nuevo");
assertThat(driver.findElement(By.id("invalid-email")).isDisplayed()).isFalse();
assertThat(driver.findElement(By.id("invalid-password")).isDisplayed()).isFalse();

Expand Down Expand Up @@ -436,4 +436,109 @@ public void loadProfilePageTest() {
assertThat(loadedPurchasesTitle).isEqualTo("Mis compras:");

}

@Test
public void cancelAccountDeletionTest() {

driver.get("http://localhost:5173/login");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("email")));
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
driver.findElement(By.id("email")).sendKeys("user@example.com");
driver.findElement(By.id("password")).sendKeys("userpass");
scrollToAndClick(By.name("login-button"));
wait.until(ExpectedConditions.urlToBe("http://localhost:5173/"));

driver.get("http://localhost:5173/me");

wait.until(ExpectedConditions.presenceOfElementLocated(By.name("delete-button")));
scrollToAndClick(By.name("delete-button"));

WebElement deleteModal = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".modal.show")));
assertThat(deleteModal.findElement(By.className("modal-title")).getText())
.isEqualTo("¿Está seguro de que desea borrar su cuenta?");
assertThat(deleteModal.findElement(By.className("modal-body")).getText())
.contains("Todos sus datos se perderán y no podrá recuperarlos.")
.contains("Esta acción no se puede deshacer.");

scrollToAndClick(By.cssSelector(".modal-footer .btn-secondary"));

wait.until(ExpectedConditions.urlToBe("http://localhost:5173/me"));

}

@Test
public void cancelAccountDeletionClosingModalTest() {

driver.get("http://localhost:5173/login");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("email")));
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
driver.findElement(By.id("email")).sendKeys("user@example.com");
driver.findElement(By.id("password")).sendKeys("userpass");
scrollToAndClick(By.name("login-button"));
wait.until(ExpectedConditions.urlToBe("http://localhost:5173/"));

driver.get("http://localhost:5173/me");

wait.until(ExpectedConditions.presenceOfElementLocated(By.name("delete-button")));
scrollToAndClick(By.name("delete-button"));

WebElement deleteModal = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".modal.show")));
assertThat(deleteModal.findElement(By.className("modal-title")).getText())
.isEqualTo("¿Está seguro de que desea borrar su cuenta?");
assertThat(deleteModal.findElement(By.className("modal-body")).getText())
.contains("Todos sus datos se perderán y no podrá recuperarlos.")
.contains("Esta acción no se puede deshacer.");
scrollToAndClick(By.cssSelector(".modal-header .btn-close"));

wait.until(ExpectedConditions.urlToBe("http://localhost:5173/me"));

}

@Test
public void deleteAccountTest() {

driver.get("http://localhost:5173/register");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("name")));
driver.findElement(By.id("name")).sendKeys("Delete");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("surname")));
driver.findElement(By.id("surname")).sendKeys("Test");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("username")));
driver.findElement(By.id("username")).sendKeys("delete_test");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("address")));
driver.findElement(By.id("address")).sendKeys("c/delete_test");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("email")));
driver.findElement(By.id("email")).sendKeys("delete_test@example.com");
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
driver.findElement(By.id("password")).sendKeys("Delete_Test1");
wait.until(ExpectedConditions.presenceOfElementLocated(By.name("register-button")));
scrollToAndClick(By.name("register-button"));
wait.until(ExpectedConditions.urlToBe("http://localhost:5173/"));

driver.get("http://localhost:5173/me");

wait.until(ExpectedConditions.presenceOfElementLocated(By.name("delete-button")));
scrollToAndClick(By.name("delete-button"));

WebElement deleteModal = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".modal.show")));
assertThat(deleteModal.findElement(By.className("modal-title")).getText())
.isEqualTo("¿Está seguro de que desea borrar su cuenta?");
assertThat(deleteModal.findElement(By.className("modal-body")).getText())
.contains("Todos sus datos se perderán y no podrá recuperarlos.")
.contains("Esta acción no se puede deshacer.");
scrollToAndClick(By.cssSelector(".modal-footer .pcmod-btn-danger"));

wait.until(ExpectedConditions.urlToBe("http://localhost:5173/"));

driver.get("http://localhost:5173/login");

wait.until(ExpectedConditions.presenceOfElementLocated(By.id("email")));
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
driver.findElement(By.id("email")).sendKeys("delete_test@example.com");
driver.findElement(By.id("password")).sendKeys("Delete_Test1");
scrollToAndClick(By.name("login-button"));

WebElement errorMessage = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("error-message")));
assertThat(errorMessage.getText()).isEqualTo("Error al iniciar sesión. Por favor, inténtelo de nuevo");

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,58 @@ void postImageWithInvalidFile() {

}

@Test
void deleteUserAsNotLoggedIn() {

assertThrows(AuthenticationCredentialsNotFoundException.class, () -> usersService.deleteUser(1L));

}

@Test
void deleteOwnUser() {
User user = usersRepository.findByEmail("testuser1@example.com").orElseThrow();

SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(
org.springframework.security.core.userdetails.User.withUsername(user.getId().toString())
.password("").authorities("ROLE_REGISTERED_USER").build(),
null, List.of(new SimpleGrantedAuthority("ROLE_REGISTERED_USER"))));

assertDoesNotThrow(() -> usersService.deleteUser(user.getId()));
assertEquals(1, usersRepository.count());

}

@Test
void deleteOtherUserAsLoggedIn() {
User user = usersRepository.findByEmail("testuser1@example.com").orElseThrow();

SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(
org.springframework.security.core.userdetails.User.withUsername(user.getId().toString())
.password("").authorities("ROLE_REGISTERED_USER").build(),
null, List.of(new SimpleGrantedAuthority("ROLE_REGISTERED_USER"))));

assertThrows(AuthorizationDeniedException.class, () -> usersService.deleteUser(2L));
assertEquals(2, usersRepository.count());

}

@Test
void deleteUsersAsAdmin() {
User admin = usersRepository.findByEmail("testadmin1@example.com").orElseThrow();
User user = usersRepository.findByEmail("testuser1@example.com").orElseThrow();

SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(
org.springframework.security.core.userdetails.User.withUsername(admin.getId().toString())
.password("").authorities("ROLE_ADMIN").build(),
null, java.util.List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))));

assertDoesNotThrow(() -> usersService.deleteUser(user.getId()));
assertDoesNotThrow(() -> usersService.deleteUser(admin.getId()));
assertEquals(0, usersRepository.count());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,36 @@ public void testAddImageWithInvalidFile() throws IOException {

assertThrows(IllegalArgumentException.class, () -> usersService.addUserImage(1L, invalidTypeImage));
}

@Test
public void testDeleteUser() {

UsersRepository usersRepository = mock(UsersRepository.class);
UsersService usersService = new UsersService(usersRepository, null, null, null);

User user = new User("user", "test", "userTest", "c/testaddress", "testuser@example.com",
passwordEncoder.encode("pass"), "REGISTERED_USER");

when(usersRepository.findById(1L)).thenReturn(java.util.Optional.of(user));

usersService.deleteUser(1L);

verify(usersRepository).deleteById(1L);

}

@Test
public void testDeleteUserNotFound() {

UsersRepository usersRepository = mock(UsersRepository.class);
UsersService usersService = new UsersService(usersRepository, null, null, null);

when(usersRepository.findById(1L)).thenReturn(java.util.Optional.empty());

usersService.deleteUser(1L);

verify(usersRepository, never()).deleteById(1L);

}

}
Loading
Loading