Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature validate adoption #93

Merged
merged 18 commits into from
Apr 6, 2024
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
11 changes: 10 additions & 1 deletion src/main/java/cat/udl/eps/softarch/demo/domain/Adoption.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cat.udl.eps.softarch.demo.domain;

import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
Expand Down Expand Up @@ -30,8 +32,15 @@ public class Adoption extends UriEntity<Long> {
private ZonedDateTime endDate;

@ManyToOne
@JsonIdentityReference(alwaysAsId = true) // Only serialize the pet ID
@JsonInclude(JsonInclude.Include.NON_NULL)
private User user; //Adopter



@ManyToOne
@JsonIdentityReference(alwaysAsId = true) // Only serialize the pet ID
@JsonInclude(JsonInclude.Include.NON_NULL) // Include pet only if it's not null
private Pet pet;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cat.udl.eps.softarch.demo.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(code = HttpStatus.CONFLICT, reason = "Bad post request")
public class InvalidPostRequest extends RuntimeException {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package cat.udl.eps.softarch.demo.handler;

import cat.udl.eps.softarch.demo.domain.Adoption;
import cat.udl.eps.softarch.demo.exceptions.InvalidPostRequest;
import org.springframework.data.rest.core.annotation.HandleAfterSave;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.HandleBeforeSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import cat.udl.eps.softarch.demo.exceptions.UnauthorizedAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
* This class defines event handlers for Adoption entity.
*/
@Component
@RepositoryEventHandler() // Ensure this handler is for MedicalRecord entity
public class AdoptionEventHandler {

private static final Logger logger = LoggerFactory.getLogger(AdoptionEventHandler.class);

/**
* These are the roles that are allowed to create an adoption.
*/
private static final String ROLE_USER = "ROLE_USER";
private static final String ROLE_SHELTER_VOLUNTEER = "ROLE_SHELTER_VOLUNTEER";
private static final String ROLE_ADMIN = "ROLE_ADMIN";

/**
* Handles actions before creating an adoption.
* @param adoption The adoption object to be created.
* @throws UnauthorizedAccessException If the user is not authorized.
* @throws InvalidPostRequest If the request is invalid.
*/
@HandleBeforeCreate
public void handleAdoptionBeforeCreate(Adoption adoption) throws UnauthorizedAccessException, InvalidPostRequest {

checkAuthorization("POST");
// If the pet is already adopted or the pet is null, an exception is thrown
if (adoption.getPet() == null || adoption.getPet().isAdopted() || adoption.getConfirmed()) {
logger.error("Pet is already adopted or bad request");
throw new InvalidPostRequest();
}
// If the adoption is successful, the adoption is in process

logger.info("Adoption for pet {} created successfully ", adoption.getPet().getName());
}

/**
* Handles actions before saving an adoption.
* @param adoption The adoption object to be saved.
* @throws UnauthorizedAccessException If the user is not authorized.
*/
@HandleBeforeSave
public void handleAdoptionBeforeSave(Adoption adoption) throws UnauthorizedAccessException {
checkAuthorization("PUT");
logger.info("Authorized save of adoption for pet {} ", adoption.getPet().getName());
}
// This function is called after editing an adoption
@HandleAfterSave
public void handleAdoptionAfterSave(Adoption adoption) throws UnauthorizedAccessException {
adoption.getPet().setAdopted(true);
logger.info("Pet {} adopted successfully", adoption.getPet().getName());
}


/**
* Checks if the user is authorized to create or edit an adoption.
* @param httpMethod The HTTP method used for the request.
* @throws UnauthorizedAccessException If the user is not authorized.
*/
private void checkAuthorization(String httpMethod) throws UnauthorizedAccessException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!isAuthorized(authentication, httpMethod)) {
throw new UnauthorizedAccessException();
}
}

/**
* Checks if the user is authorized and checks the role of the user.
* @param authentication The authentication object of the user.
* @param HTTPMethod The HTTP method used for the request.
* @return True if the user is authorized, false otherwise.
*/
private boolean isAuthorized(Authentication authentication, String HTTPMethod) {
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
List<String> requiredAuthorities;

if (HTTPMethod.equals("PUT")) {
requiredAuthorities = Arrays.asList(ROLE_SHELTER_VOLUNTEER, ROLE_ADMIN);
}
else if (HTTPMethod.equals("POST")) {
requiredAuthorities = Arrays.asList(ROLE_SHELTER_VOLUNTEER, ROLE_ADMIN, ROLE_USER);
}
else {
requiredAuthorities = Arrays.asList(ROLE_ADMIN, ROLE_SHELTER_VOLUNTEER);
}
return authentication.getAuthorities().stream()
.anyMatch(grantedAuthority -> requiredAuthorities.contains(grantedAuthority.getAuthority()));
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cat.udl.eps.softarch.demo.repository;

import cat.udl.eps.softarch.demo.domain.Adoption;
import cat.udl.eps.softarch.demo.domain.Location;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;

public interface AdoptionRepository extends CrudRepository<Adoption, Long>, PagingAndSortingRepository<Adoption, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package cat.udl.eps.softarch.demo.steps;


import cat.udl.eps.softarch.demo.domain.Adoption;
import cat.udl.eps.softarch.demo.domain.Pet;
import cat.udl.eps.softarch.demo.repository.AdoptionRepository;
import cat.udl.eps.softarch.demo.repository.PetRepository;
import cat.udl.eps.softarch.demo.repository.UserRepository;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;

import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SuppressWarnings("ALL")
public class ProcessAdoptionStepDefs {


@Autowired
StepDefs stepDefs;

@Autowired
UserRepository userRepository;

@Autowired
PetRepository petRepository;

@Autowired
AdoptionRepository adoptionRepository;

protected ResultActions result;


@And("I receive a confirmation message for adopting the pet")
public void iReceiveAConfirmationMessageForAdoptingThePet() throws Throwable {
result.andExpect(status().isOk())
.andExpect(jsonPath("$.message", is("Adoption successful")));

}

@Given("There is an available pet with name {string} i want to adopt")
public void thereIsAnAvailablePetWithName(String arg0) {

Pet pet = new Pet();
pet.setName(arg0);
pet.setAdopted(false);
pet.setColor("color");
pet.setSize("size");
pet.setWeight(1.0);
pet.setAge("age");
pet.setDescription("description");
pet.setBreed("breed");
petRepository.save(pet);

}

@When("I request to adopt the pet with name {string}")
public void iRequestToAdoptThePetWithName(String arg0) throws Throwable {

Adoption adoption = new Adoption();
adoption.setPet(petRepository.findByName(arg0).get(0));
adoption.setUser(userRepository.findAll().iterator().next());
adoption.setStartDate(ZonedDateTime.now());
adoption.setConfirmed(false);
adoption.setType("Adoption");
adoption.setEndDate(null);

stepDefs.result = stepDefs.mockMvc.perform(
post("/adoptions")
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(adoption))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate()))
.andDo(print());

}



@When("I request to adopt without a pet")
public void iRequestToAdoptWithoutAPet() throws Throwable{
// Proceed with adoption logic
Adoption adoption = new Adoption();
adoption.setUser(userRepository.findAll().iterator().next());
adoption.setStartDate(ZonedDateTime.now());
adoption.setConfirmed(false);
adoption.setType("Adoption");
adoption.setEndDate(null);


stepDefs.result = stepDefs.mockMvc.perform(
post("/adoptions")
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(adoption))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate()))
.andDo(print());

}

@And("The pet with name {string} is already adopted")
public void thePetWithNameIsAlreadyAdopted(String arg0) {

Pet pet = new Pet();
pet.setName(arg0);
pet.setAdopted(true);
pet.setColor("color");
pet.setSize("size");
pet.setWeight(1.0);
pet.setAge("age");
pet.setDescription("description");
pet.setBreed("breed");
petRepository.save(pet);


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cat.udl.eps.softarch.demo.steps;



import cat.udl.eps.softarch.demo.domain.Pet;
import cat.udl.eps.softarch.demo.domain.Adoption;
import cat.udl.eps.softarch.demo.repository.AdoptionRepository;
import cat.udl.eps.softarch.demo.repository.PetRepository;
import cat.udl.eps.softarch.demo.repository.UserRepository;
import io.cucumber.java.en.And;
import io.cucumber.java.en.When;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;

import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@SuppressWarnings("ALL")
public class ValidateAdoptionStepDefs {

@Autowired
StepDefs stepDefs;

@Autowired
UserRepository userRepository;

@Autowired
PetRepository petRepository;

@Autowired
AdoptionRepository adoptionRepository;

protected ResultActions result;


@And("There is a dog with a pending adoption request from an user")
public void thereIsAPendingAdoptionRequestForPetFromUser() {
Pet pet = new Pet();
pet.setName("Pet");
pet.setAdopted(false);
pet.setColor("color");
pet.setSize("size");
pet.setWeight(1.0);
pet.setAge("age");
pet.setDescription("description");
pet.setBreed("breed");
petRepository.save(pet);


Adoption adoption = new Adoption();
adoption.setConfirmed(false);
adoption.setStartDate(ZonedDateTime.now());
adoption.setUser(userRepository.findAll().iterator().next());
adoption.setPet(petRepository.findAll().iterator().next());
adoption.setType("Adoption");
adoption.setEndDate(null);
adoptionRepository.save(adoption);

}

@When("I validate the adoption request")
public void iValidateTheAdoptionRequestForPetFromUser() throws Throwable {
Adoption existingAdoption = adoptionRepository.findAll().iterator().next();
existingAdoption.setConfirmed(true);

stepDefs.result = stepDefs.mockMvc.perform(
put("/adoptions/" + existingAdoption.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(existingAdoption))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate()))
.andDo(print());

}


}
Loading
Loading