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 edit medical record #92

Merged
merged 13 commits into from
Apr 6, 2024
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 All @@ -14,7 +16,7 @@
public class MedicalRecord extends UriEntity<Long> {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue()
private Long id;

@NotBlank
Expand All @@ -27,5 +29,7 @@ public class MedicalRecord extends UriEntity<Long> {
private ZonedDateTime date;

@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;
}
1 change: 1 addition & 0 deletions src/main/java/cat/udl/eps/softarch/demo/domain/Pet.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class Pet extends UriEntity<Long> {
@GeneratedValue
Long id;


String name;
boolean isAdopted;
String color;
Expand Down
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.FORBIDDEN, reason = "Unauthorized access")
public class UnauthorizedAccessException extends RuntimeException {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cat.udl.eps.softarch.demo.handler;

import cat.udl.eps.softarch.demo.domain.MedicalRecord;
import cat.udl.eps.softarch.demo.exceptions.UnauthorizedAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 org.springframework.stereotype.Component;

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

@Component
@RepositoryEventHandler() // Ensure this handler is for MedicalRecord entity
public class MedicalRecordEventHandler {

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

private static final String ROLE_SHELTER_VOLUNTEER = "ROLE_SHELTER_VOLUNTEER";
private static final String ROLE_ADMIN = "ROLE_ADMIN";

/**
* Handles actions before creating a medical record.
* @param medicalRecord the medical record to be created
* @throws UnauthorizedAccessException if the user is not authorized to create a medical record
*/
@HandleBeforeCreate
public void handleMedicalRecordBeforeCreate(MedicalRecord medicalRecord) throws UnauthorizedAccessException {
checkAuthorization();
logger.info("Authorized creation of a new medical record by user: {}", getCurrentUsername());
}

/**
* Handles actions before saving (updating) a medical record.
*/
@HandleBeforeSave
public void handleMedicalRecordBeforeSave(MedicalRecord medicalRecord) throws UnauthorizedAccessException {
checkAuthorization();
logger.info("Authorized save of medical record by user: {}", getCurrentUsername());
}

/**
* Handles actions after saving a medical record.
* @param medicalRecord the saved medical record
*/
@HandleAfterSave
public void handleMedicalRecordPostSave(MedicalRecord medicalRecord) {
logger.info("Medical record for pet {} saved successfully", medicalRecord.getPet().getName());
}

private void checkAuthorization() throws UnauthorizedAccessException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!isAuthorized(authentication)) {
throw new UnauthorizedAccessException();
}
}

private boolean isAuthorized(Authentication authentication) {
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
List<String> requiredAuthorities = Arrays.asList(ROLE_SHELTER_VOLUNTEER, ROLE_ADMIN);
return authentication.getAuthorities().stream()
.anyMatch(grantedAuthority -> requiredAuthorities.contains(grantedAuthority.getAuthority()));
}

private String getCurrentUsername() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null ? authentication.getName() : "anonymous";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cat.udl.eps.softarch.demo.repository;

import cat.udl.eps.softarch.demo.domain.MedicalRecord;
import cat.udl.eps.softarch.demo.domain.Pet;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import java.util.List;

@RepositoryRestResource
public interface MedicalRecordRepository extends CrudRepository < MedicalRecord, Long > , PagingAndSortingRepository < MedicalRecord, Long > {

List < MedicalRecord > findByPet(@Param("pet") Pet pet);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cat.udl.eps.softarch.demo.steps;

import cat.udl.eps.softarch.demo.domain.MedicalRecord;
import cat.udl.eps.softarch.demo.domain.Pet;
import cat.udl.eps.softarch.demo.repository.PetRepository;
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 java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;

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


public class AddMedicalRecordStepDefs {

@Autowired
private StepDefs stepDefs;

@Autowired
PetRepository petRepository;


@Given("a pet exists in the system")
public void aPetExistsInTheSystem() {
var pet = new Pet();

petRepository.save(pet); // Save the pet to the database
}

@When("I add a new medical record for a pet with issue {string}, description {string}, and date {string}")
public void iAddANewMedicalRecordForAPetWithIssueDescriptionAndDate(String issue, String description, String date) throws Throwable {
MedicalRecord newRecord = new MedicalRecord();
newRecord.setDescription(description);
newRecord.setIssue(issue);
newRecord.setDate(ZonedDateTime.parse(date));
newRecord.setPet(petRepository.findAll().iterator().next());

// Mock a POST request to /medicalRecords
stepDefs.result = stepDefs.mockMvc.perform(
post("/medicalRecords")
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(newRecord))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate()))
.andDo(print());

}



@When("I add a new medical record for a pet with issue {string}, description {string} and no date")
public void iAddANewMedicalRecordForAPetWithIssueDescriptionAndNoDate(String issue, String description) throws Throwable {
MedicalRecord recordWithoutDate = new MedicalRecord();
recordWithoutDate.setDescription(description);
recordWithoutDate.setIssue(issue);
//No data added
recordWithoutDate.setPet(petRepository.findAll().iterator().next());

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

@When("I try to add a medical record for a pet")
public void iTryToAddAMedicalRecordForAPet() throws Exception {
MedicalRecord medicalRecord = new MedicalRecord();
medicalRecord.setDescription("Description");
medicalRecord.setIssue("Issue");
medicalRecord.setDate(ZonedDateTime.now());
medicalRecord.setPet(petRepository.findAll().iterator().next());

stepDefs.result = stepDefs.mockMvc.perform(
post("/medicalRecords")
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(medicalRecord))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate())
)
.andDo(print());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cat.udl.eps.softarch.demo.steps;

import cat.udl.eps.softarch.demo.domain.MedicalRecord;
import cat.udl.eps.softarch.demo.domain.Pet;
import cat.udl.eps.softarch.demo.repository.MedicalRecordRepository;
import cat.udl.eps.softarch.demo.repository.PetRepository;
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 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;

public class EditMedicalRecordStepDefs {

@Autowired
private StepDefs stepDefs;

@Autowired
MedicalRecordRepository medicalRecordRepository;

@Autowired
PetRepository petRepository;

@And("a medical record exists for the pet")
public void aMedicalRecordExistsForThePet() {
Pet pet = petRepository.findAll().iterator().next();

MedicalRecord existingMedicalRecord;
existingMedicalRecord = new MedicalRecord();
existingMedicalRecord.setPet(pet);
existingMedicalRecord.setIssue("Initial Issue");
existingMedicalRecord.setDescription("Initial Description");
existingMedicalRecord.setDate(ZonedDateTime.now());
medicalRecordRepository.save(existingMedicalRecord);

}

@When("I edit the medical record for a pet with new issue {string}, new description {string}, and new date {string}")
public void iEditTheMedicalRecordForAPetWithNewIssueNewDescriptionAndNewDate(String issue, String description, String date) throws Throwable {
MedicalRecord existingMedicalRecord = medicalRecordRepository.findAll().iterator().next();
existingMedicalRecord.setIssue(issue);
existingMedicalRecord.setDescription(description);
existingMedicalRecord.setDate(ZonedDateTime.parse(date));

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

@When("I edit the medical record for a pet with new issue {string}, new description {string}")
public void iEditTheMedicalRecordForAPetWithNewIssueNewDescription(String issue, String description) throws Throwable {
MedicalRecord existingMedicalRecord = medicalRecordRepository.findAll().iterator().next();

existingMedicalRecord.setIssue(issue);
existingMedicalRecord.setDescription(description);
// Keeping the original date

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

@When("I try to edit a medical record for a pet")
public void iTryToEditAMedicalRecordForAPet() throws Exception {
MedicalRecord existingMedicalRecord = medicalRecordRepository.findAll().iterator().next();

stepDefs.result = stepDefs.mockMvc.perform(
put("/medicalRecords/" + existingMedicalRecord.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(stepDefs.mapper.writeValueAsString(existingMedicalRecord))
.characterEncoding(StandardCharsets.UTF_8)
.with(AuthenticationStepDefs.authenticate()))
.andDo(print());
}
}
42 changes: 42 additions & 0 deletions src/test/resources/features/AddMedicalRecord.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Feature: Add Medical Record
In order to maintain an accurate health history for pets
As a shelter volunteer
I want to add medical records to pets' profiles

Background:
Given a pet exists in the system
Given There is a registered user with username "user" and password "password" and email "[email protected]"
Given There is a registered admin with name "admin" and password "password" and email "[email protected]"
Given There is a registered volunteer with name "volunteer" and password "password" and email "[email protected]"


Scenario: Add a valid medical record to an existing pet as Volunteer
Given I login as "volunteer" with password "password"
When I add a new medical record for a pet with issue "Allergy", description "Seasonal allergy", and date "2024-03-07T14:00:00Z"
Then The response code is 201

Scenario: Add medical record with empty issue as Volunteer
Given I login as "volunteer" with password "password"
When I add a new medical record for a pet with issue "", description "Missing vaccine", and date "2024-03-07T14:00:00Z"
Then The response code is 400

Scenario: Add medical record with empty description as Volunteer
Given I login as "volunteer" with password "password"
When I add a new medical record for a pet with issue "Vaccination", description "", and date "2024-03-07T14:00:00Z"
Then The response code is 400

Scenario: Add medical record without date as Volunteer
Given I login as "volunteer" with password "password"
When I add a new medical record for a pet with issue "Injury", description "Minor cut on paw" and no date
Then The response code is 400

Scenario: Attempt to add a medical record as a normal user
Given I login as "user" with password "password"
When I try to add a medical record for a pet
Then The response code is 403
And The error message is "Unauthorized access"

Scenario: Attempt to add a medical record as an admin
Given I login as "admin" with password "password"
When I try to add a medical record for a pet
Then The response code is 201
Loading
Loading