Skip to content

Commit

Permalink
Merge pull request #2813 from objectcomputing/bugfix-2807/partial-vol…
Browse files Browse the repository at this point in the history
…unteer-hours

Support floating point hours for volunteering.
  • Loading branch information
mkimberlin authored Jan 10, 2025
2 parents 08d313e + 0ea87c8 commit 8f0a304
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ public class VolunteeringEvent {

@Column(name = "hours")
@Schema(description = "number of hours spent volunteering")
@TypeDef(type = DataType.INTEGER)
private int hours;
@TypeDef(type = DataType.DOUBLE)
private double hours;

@Nullable
@Column(name = "notes")
@TypeDef(type = DataType.STRING)
@Schema(description = "notes about the volunteering event")
private String notes;

public VolunteeringEvent(UUID relationshipId, LocalDate eventDate, int hours, String notes) {
public VolunteeringEvent(UUID relationshipId, LocalDate eventDate, double hours, String notes) {
this(null, relationshipId, eventDate, hours, notes);
}

Expand All @@ -79,4 +79,4 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(id, relationshipId, eventDate, hours, notes);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public class VolunteeringEventDTO {

@NotNull
@Schema(description = "number of hours spent volunteering")
private Integer hours;
private Double hours;

@Nullable
@Schema(description = "notes about the volunteering event")
private String notes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE volunteering_event
ALTER COLUMN hours TYPE float;
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ default VolunteeringRelationship createVolunteeringRelationship(UUID memberId, U
return getVolunteeringRelationshipRepository().save(new VolunteeringRelationship(memberId, organizationId, startDate, endDate, active));
}

default VolunteeringEvent createVolunteeringEvent(UUID relationshipId, LocalDate now, int i, String notes) {
default VolunteeringEvent createVolunteeringEvent(UUID relationshipId, LocalDate now, double i, String notes) {
return getVolunteeringEventRepository().save(new VolunteeringEvent(relationshipId, now, i, notes));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

@Property(name = VolunteeringClients.Event.ENABLED, value = "true")
class VolunteeringEventControllerTest extends TestContainersSuite implements MemberProfileFixture, RoleFixture, VolunteeringFixture {
static final double fiveHours = 5.0;
static final double tenHours = 10.0;

@Inject
VolunteeringClients.Event eventClient;
Expand Down Expand Up @@ -63,7 +65,7 @@ void memberCanCreateEventForTheirRelationships() {
LocalDate now = LocalDate.now();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);

var event = new VolunteeringEventDTO(relationship.getId(), now, 10, "Notes");
var event = new VolunteeringEventDTO(relationship.getId(), now, tenHours, "Notes");
var createdEvent = eventClient.create(timAuth, event);

assertEquals(HttpStatus.CREATED, createdEvent.getStatus());
Expand All @@ -83,7 +85,7 @@ void memberCannotCreateEventForSomeoneElseRelationships() {
LocalDate now = LocalDate.now();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);

var event = new VolunteeringEventDTO(relationship.getId(), now, 10, "Notes");
var event = new VolunteeringEventDTO(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), MEMBER_ROLE);
Expand All @@ -104,7 +106,7 @@ void memberWithPermissionCanCreateEventForSomeoneElseRelationships() {
MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), ADMIN_ROLE);

var event = new VolunteeringEventDTO(relationship.getId(), now, 10, "Notes");
var event = new VolunteeringEventDTO(relationship.getId(), now, tenHours, "Notes");
var createdEvent = eventClient.create(bobAuth, event);

assertEquals(HttpStatus.CREATED, createdEvent.getStatus());
Expand All @@ -124,9 +126,9 @@ void memberCanUpdateTheirOwnEvents() {

VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

var updated = eventClient.update(timAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, 5, "New notes"));
var updated = eventClient.update(timAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, fiveHours, "New notes"));
assertEquals(event.getId(), updated.getId());
assertEquals("New notes", updated.getNotes());
}
Expand All @@ -138,12 +140,12 @@ void memberCannotUpdateOthersEvents() {

VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), MEMBER_ROLE);

var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, 5, "New notes")));
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, fiveHours, "New notes")));
assertEquals(HttpStatus.BAD_REQUEST, e.getStatus());
assertEquals("Member %s does not have permission to update Volunteering event for relationship %s".formatted(bob.getId(), relationship.getId()), e.getMessage());
}
Expand All @@ -157,12 +159,12 @@ void memberCannotUpdateTheirEventToSomeoneElse() {

VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
VolunteeringRelationship bobRelationship = createVolunteeringRelationship(bob.getId(), organization.getId(), now);

var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(timAuth, event.getId(), new VolunteeringEventDTO(bobRelationship.getId(), now, 5, "New notes")));
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(timAuth, event.getId(), new VolunteeringEventDTO(bobRelationship.getId(), now, fiveHours, "New notes")));
assertEquals(HttpStatus.BAD_REQUEST, e.getStatus());
assertEquals("Member %s does not have permission to update Volunteering event for relationship %s".formatted(tim.getId(), bobRelationship.getId()), e.getMessage());
}
Expand All @@ -175,13 +177,13 @@ void memberCannotUpdateSomeoneElseEventToTheirs() {

VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), MEMBER_ROLE);
VolunteeringRelationship bobRelationship = createVolunteeringRelationship(bob.getId(), organization.getId(), now);

var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(bobRelationship.getId(), now, 5, "New notes")));
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(bobRelationship.getId(), now, fiveHours, "New notes")));
assertEquals(HttpStatus.BAD_REQUEST, e.getStatus());
assertEquals("Member %s does not have permission to update Volunteering event for relationship %s".formatted(bob.getId(), relationship.getId()), e.getMessage());
}
Expand All @@ -192,13 +194,13 @@ void memberCannotHackUpdateOthersEventsWithTheirOwnRelationship() {
MemberProfile tim = createADefaultMemberProfile();
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), MEMBER_ROLE);
VolunteeringRelationship bobsRelationship = createVolunteeringRelationship(bob.getId(), organization.getId(), now);

var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(bobsRelationship.getId(), now, 5, "New notes")));
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(bobsRelationship.getId(), now, fiveHours, "New notes")));
assertEquals(HttpStatus.BAD_REQUEST, e.getStatus());
assertEquals("Member %s does not have permission to update Volunteering event for relationship %s".formatted(bob.getId(), relationship.getId()), e.getMessage());
}
Expand All @@ -209,12 +211,12 @@ void memberCanUpdateOthersEventsWithProperPermission() {
MemberProfile tim = createADefaultMemberProfile();
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), ADMIN_ROLE);

var updated = eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, 5, "New notes"));
var updated = eventClient.update(bobAuth, event.getId(), new VolunteeringEventDTO(relationship.getId(), now, fiveHours, "New notes"));
assertEquals(event.getId(), updated.getId());
assertEquals("New notes", updated.getNotes());
}
Expand All @@ -226,7 +228,7 @@ void memberCanDeleteTheirOwnEvents() {
String timAuth = auth(tim.getWorkEmail(), MEMBER_ROLE);
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

var deletedEvent = eventClient.delete(timAuth, event.getId());
assertEquals(HttpStatus.OK, deletedEvent.getStatus());
Expand All @@ -238,7 +240,7 @@ void memberCannotDeleteOthersEvents() {
MemberProfile tim = createADefaultMemberProfile();
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), MEMBER_ROLE);
Expand All @@ -254,7 +256,7 @@ void memberWithPermissionCanDeleteOthersEvents() {
MemberProfile tim = createADefaultMemberProfile();
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

MemberProfile bob = memberWithoutBoss("bob");
String bobAuth = auth(bob.getWorkEmail(), ADMIN_ROLE);
Expand Down Expand Up @@ -304,13 +306,13 @@ void eventListCanBeFiltered() {
var bobClosed = createVolunteeringRelationship(bob.getId(), closedOrg.getId(), now.minusDays(100), now.minusDays(50), false);
var clairClosed = createVolunteeringRelationship(claire.getId(), closedOrg.getId(), now.minusDays(1), now);

var aliceLiftEvent1 = createVolunteeringEvent(aliceLiftForLife.getId(), now.minusDays(2), 10, "aliceLiftEvent1"); // 2 days ago
var aliceLiftEvent1 = createVolunteeringEvent(aliceLiftForLife.getId(), now.minusDays(2), tenHours, "aliceLiftEvent1"); // 2 days ago
var aliceLiftEvent2 = createVolunteeringEvent(aliceLiftForLife.getId(), now, 8, "aliceLiftEvent2"); // today
var bobLiftEvent1 = createVolunteeringEvent(bobLiftForLife.getId(), now, 6, "bobLiftEvent1"); // today
var clairLiftEvent1 = createVolunteeringEvent(claireLiftForLife.getId(), now.minusDays(3), 4, "clairLiftEvent1"); // 3 days ago
var aliceFoodEvent1 = createVolunteeringEvent(aliceFood.getId(), now.minusDays(20), 2, "aliceFoodEvent1"); // 20 days ago
var clairFoodEvent1 = createVolunteeringEvent(claireFood.getId(), now, 1, "clairFoodEvent1"); // today
var bobClosedEvent1 = createVolunteeringEvent(bobClosed.getId(), now.minusDays(76), 10, "bobClosedEvent1"); // 76 days ago
var bobClosedEvent1 = createVolunteeringEvent(bobClosed.getId(), now.minusDays(76), tenHours, "bobClosedEvent1"); // 76 days ago
var clairClosedEvent1 = createVolunteeringEvent(clairClosed.getId(), now.minusDays(1), 0, "clairClosedEvent1"); // yesterday

// List all events, sorted by event date and then by organization name
Expand Down Expand Up @@ -353,10 +355,10 @@ void relationshipMustExist() {
String timAuth = auth(tim.getWorkEmail(), MEMBER_ROLE);
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");
UUID randomId = UUID.randomUUID();

VolunteeringEventDTO newEvent = new VolunteeringEventDTO(randomId, now, 10, "Notes");
VolunteeringEventDTO newEvent = new VolunteeringEventDTO(randomId, now, tenHours, "Notes");

// Creating an event with a non-existent relationship should fail
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.create(timAuth, newEvent));
Expand All @@ -376,9 +378,9 @@ void eventDateMustBeSet() {
String timAuth = auth(tim.getWorkEmail(), MEMBER_ROLE);
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

VolunteeringEventDTO newEvent = new VolunteeringEventDTO(relationship.getId(), null, 10, "Notes");
VolunteeringEventDTO newEvent = new VolunteeringEventDTO(relationship.getId(), null, tenHours, "Notes");

// Creating an event with a null date should fail
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.create(timAuth, newEvent));
Expand All @@ -400,9 +402,9 @@ void hoursMustBeNonNegative() {
String timAuth = auth(tim.getWorkEmail(), MEMBER_ROLE);
VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");

VolunteeringEventDTO newEvent = new VolunteeringEventDTO(relationship.getId(), now, -1, "Notes");
VolunteeringEventDTO newEvent = new VolunteeringEventDTO(relationship.getId(), now, -1.0, "Notes");

// Creating an event with negative hours should fail
var e = assertThrows(HttpClientResponseException.class, () -> eventClient.create(timAuth, newEvent));
Expand All @@ -422,7 +424,7 @@ void hoursAreRequired() {

VolunteeringOrganization organization = createDefaultVolunteeringOrganization();
VolunteeringRelationship relationship = createVolunteeringRelationship(tim.getId(), organization.getId(), now);
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, 10, "Notes");
VolunteeringEvent event = createVolunteeringEvent(relationship.getId(), now, tenHours, "Notes");
String postBody = """
{
"relationshipId": "%s",
Expand Down

0 comments on commit 8f0a304

Please sign in to comment.