diff --git a/src/main/java/uk/ac/sanger/sccp/stan/GraphQLMutation.java b/src/main/java/uk/ac/sanger/sccp/stan/GraphQLMutation.java index 2a78478a..8b77e9a8 100644 --- a/src/main/java/uk/ac/sanger/sccp/stan/GraphQLMutation.java +++ b/src/main/java/uk/ac/sanger/sccp/stan/GraphQLMutation.java @@ -389,6 +389,17 @@ public DataFetcher setEquipmentEnabled() { }; } + public DataFetcher renameEquipment() { + return dfe -> { + User user = checkUser(dfe, User.Role.admin); + Integer equipmentId = dfe.getArgument("equipmentId"); + requireNonNull(equipmentId, "equipmentId not specified"); + String name = dfe.getArgument("name"); + logRequest("RenameEquipment", user, String.format("(equipmentId=%s, name=%s)", equipmentId, repr(name))); + return equipmentAdminService.renameEquipment(equipmentId, name); + }; + } + public DataFetcher addDestructionReason() { return adminAdd(destructionReasonAdminService::addNew, "AddDestructionReason", "text"); } diff --git a/src/main/java/uk/ac/sanger/sccp/stan/GraphQLProvider.java b/src/main/java/uk/ac/sanger/sccp/stan/GraphQLProvider.java index aa963a2e..0895a80e 100644 --- a/src/main/java/uk/ac/sanger/sccp/stan/GraphQLProvider.java +++ b/src/main/java/uk/ac/sanger/sccp/stan/GraphQLProvider.java @@ -149,6 +149,7 @@ private RuntimeWiring buildWiring() { .dataFetcher("setCommentEnabled", transact(graphQLMutation.setCommentEnabled())) .dataFetcher("addEquipment", transact(graphQLMutation.addEquipment())) .dataFetcher("setEquipmentEnabled", transact(graphQLMutation.setEquipmentEnabled())) + .dataFetcher("renameEquipment", transact(graphQLMutation.renameEquipment())) .dataFetcher("addHmdmc", transact(graphQLMutation.addHmdmc())) .dataFetcher("setHmdmcEnabled", transact(graphQLMutation.setHmdmcEnabled())) .dataFetcher("addDestructionReason", transact(graphQLMutation.addDestructionReason())) diff --git a/src/main/java/uk/ac/sanger/sccp/stan/service/EquipmentAdminService.java b/src/main/java/uk/ac/sanger/sccp/stan/service/EquipmentAdminService.java index dea775bc..711c6298 100644 --- a/src/main/java/uk/ac/sanger/sccp/stan/service/EquipmentAdminService.java +++ b/src/main/java/uk/ac/sanger/sccp/stan/service/EquipmentAdminService.java @@ -48,6 +48,17 @@ public Equipment addEquipment(String category, String name) { return equipmentRepo.save(new Equipment(name, category.toLowerCase())); } + public Equipment renameEquipment(int equipmentId, String newName) { + newName = trimAndRequire(newName, "Name not supplied."); + equipmentNameValidator.checkArgument(newName); + Equipment eq = equipmentRepo.getById(equipmentId); + if (newName.equals(eq.getName())) { + return eq; + } + eq.setName(newName); + return equipmentRepo.save(eq); + } + public Equipment setEquipmentEnabled(int equipmentId, boolean enabled) { Equipment eq = equipmentRepo.getById(equipmentId); if (eq.isEnabled() != enabled) { diff --git a/src/main/resources/schema.graphqls b/src/main/resources/schema.graphqls index d43c506e..06721fb5 100644 --- a/src/main/resources/schema.graphqls +++ b/src/main/resources/schema.graphqls @@ -1913,6 +1913,8 @@ type Mutation { setCommentEnabled(commentId: Int!, enabled: Boolean!): Comment! """Create a new piece of equipment that users can record using in future operations.""" addEquipment(category: String!, name: String!): Equipment! + """Rename existing equipment.""" + renameEquipment(equipmentId: Int!, name: String!): Equipment! """Enable or disable a piece of equipment.""" setEquipmentEnabled(equipmentId: Int!, enabled: Boolean!): Equipment! """Create a new reason that users can record when destroying labware.""" diff --git a/src/test/java/uk/ac/sanger/sccp/stan/service/TestEquipmentAdminService.java b/src/test/java/uk/ac/sanger/sccp/stan/service/TestEquipmentAdminService.java index 08a9ae26..7ffd5221 100644 --- a/src/test/java/uk/ac/sanger/sccp/stan/service/TestEquipmentAdminService.java +++ b/src/test/java/uk/ac/sanger/sccp/stan/service/TestEquipmentAdminService.java @@ -3,9 +3,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.*; import org.mockito.stubbing.OngoingStubbing; -import uk.ac.sanger.sccp.stan.Matchers; import uk.ac.sanger.sccp.stan.model.Equipment; import uk.ac.sanger.sccp.stan.repo.EquipmentRepo; @@ -17,6 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import static uk.ac.sanger.sccp.stan.Matchers.returnArgument; /** * Tests {@link EquipmentAdminService} @@ -31,8 +31,8 @@ public class TestEquipmentAdminService { void setup() { mockEquipmentRepo = mock(EquipmentRepo.class); service = new EquipmentAdminService(mockEquipmentRepo, - new StringValidator("Equipment name", 2, 8, StringValidator.CharacterType.ALPHA), - new StringValidator("Equipment category", 2, 8, StringValidator.CharacterType.ALPHA)); + new StringValidator("Equipment category", 2, 8, StringValidator.CharacterType.ALPHA), + new StringValidator("Equipment name", 2, 8, StringValidator.CharacterType.ALPHA)); } @ParameterizedTest @@ -63,14 +63,14 @@ public void testGetEquipment(String category, boolean includeDisabled) { @CsvSource(value={ ",Bananas,Category not supplied.", "scanner,,Name not supplied.", - "sc@nner,Bananas,Equipment name \"sc@nner\" contains invalid characters \"@\".", - "scanner,B@nanas,Equipment category \"B@nanas\" contains invalid characters \"@\".", + "sc@nner,Bananas,Equipment category \"sc@nner\" contains invalid characters \"@\".", + "scanner,B@nanas,Equipment name \"B@nanas\" contains invalid characters \"@\".", "scanner,Bananas,", "' SCANNER ', ' Bananas ',", }) public void testAddEquipment(String category, String name, String expectedErrorMessage) { if (expectedErrorMessage==null) { - when(mockEquipmentRepo.save(any())).then(Matchers.returnArgument()); + when(mockEquipmentRepo.save(any())).then(returnArgument()); Equipment equipment = service.addEquipment(category, name); assertNotNull(equipment); verify(mockEquipmentRepo).save(equipment); @@ -99,7 +99,7 @@ public void testAddEquipmentDupe() { public void testSetEquipmentEnabled(boolean wasEnabled, boolean enabled) { Equipment equipment = new Equipment(10, "scanner", "Bananas", wasEnabled); when(mockEquipmentRepo.getById(equipment.getId())).thenReturn(equipment); - when(mockEquipmentRepo.save(any())).then(Matchers.returnArgument()); + when(mockEquipmentRepo.save(any())).then(returnArgument()); assertSame(equipment, service.setEquipmentEnabled(equipment.getId(), enabled)); @@ -110,4 +110,38 @@ public void testSetEquipmentEnabled(boolean wasEnabled, boolean enabled) { verify(mockEquipmentRepo).save(equipment); } } + + @ParameterizedTest + @NullSource + @ValueSource(strings={"", " "}) + public void testRenameEquipment_noName(String name) { + assertThat(assertThrows(IllegalArgumentException.class, () -> service.renameEquipment(17, name))) + .hasMessage("Name not supplied."); + verifyNoInteractions(mockEquipmentRepo); + } + + @Test + public void testRename_invalidName() { + assertThat(assertThrows(IllegalArgumentException.class, () -> service.renameEquipment(17, "Name!"))) + .hasMessageMatching(".*name.*invalid.*"); + verifyNoInteractions(mockEquipmentRepo); + } + + @ParameterizedTest + @ValueSource(booleans={false,true}) + public void testRename(boolean same) { + Equipment eq = new Equipment(17, "Alpha", "bookcase", true); + String newName = (same ? eq.getName() : "Beta"); + int id = eq.getId(); + when(mockEquipmentRepo.getById(id)).thenReturn(eq); + when(mockEquipmentRepo.save(any())).then(returnArgument()); + + assertSame(eq, service.renameEquipment(id, newName)); + assertEquals(newName, eq.getName()); + if (same) { + verify(mockEquipmentRepo, never()).save(any()); + } else { + verify(mockEquipmentRepo).save(eq); + } + } }