Skip to content

Commit

Permalink
Merge pull request #55 from Matoking/tuomokar
Browse files Browse the repository at this point in the history
Reference key is unique
  • Loading branch information
tuomokar committed May 3, 2016
2 parents 7cebb1a + 9f5524e commit 76b5821
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 22 deletions.
33 changes: 20 additions & 13 deletions src/main/java/ohtuhatut/controller/ReferenceController.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,25 @@ public String editReference(Model model, @PathVariable Long id) {
* Handles the POST request for editing a reference. The method takes the
* reference as an instance of the superclass from which it is then bound to
* the correct subclass type. The method checks if the given reference has
* any mandatory values left empty, and if so, returns the editing view
* along with the appropriate error message. Otherwise the edited reference
* gets saved to the database and user gets redirected to the page of the
* reference.
* any mandatory values left empty and if the given key is in use on any
* other references, and if so, returns the editing view along with the
* appropriate error message. Otherwise the edited reference gets saved to
* the database and user gets redirected to the page of the reference.
*/
@RequestMapping(value = "/{id}/edit", method = RequestMethod.POST)
public String updateReference(@ModelAttribute Reference reference,
@PathVariable Long id, RedirectAttributes attr, Model model) {

reference = referenceService.bindReference(reference);

if (!reference.getEmptyMandatoryFields().isEmpty()) {
if (!reference.getEmptyMandatoryFields().isEmpty() || referenceService.referenceKeyAlreadyUsedOnSomeOtherReference(reference)) {
model.addAttribute("emptyFieldMessage", referenceService.getErrorMessages(reference.getEmptyMandatoryFields()));
model.addAttribute("keyUsed", referenceService.keyIsInUseOnSomeOtherReferenceErrorMessage(reference));

model.addAttribute("emptyFields", reference.getEmptyMandatoryFields());
model.addAttribute("reference", referenceService.getReference(reference.getId()));
return "references/reference_edit";
}

}
referenceService.saveReference(reference);

attr.addAttribute("id", reference.getId());
Expand Down Expand Up @@ -133,26 +134,32 @@ public String newReference(Model model, @RequestParam(value = "type", required =

/**
* Handles the POST request for creating a new reference. If the user left
* any mandatory fields empty, the method returns the view to create a new
* reference along with an error message informing the user what fields were
* left empty. Otherwise the reference is saved to the database and the user
* is redirected to the newly created reference's page.
* any mandatory fields empty, or if the key given is already in use,
* the method returns the view to create a new reference along with an error
* message informing the user what fields were left empty or that key is in
* use. Otherwise the reference is saved to the database and the user is
* redirected to the newly created reference's page.
*/
@RequestMapping(value = "/new", method = RequestMethod.POST)
public String newReferenceCreate(@ModelAttribute Reference reference,
RedirectAttributes attr,
Model model) {

reference = referenceService.bindReference(reference);
reference = referenceService.bindReference(reference);

if (!reference.getEmptyMandatoryFields().isEmpty()) {
String key = reference.getKey();

if (!reference.getEmptyMandatoryFields().isEmpty() || referenceService.referenceKeyAlreadyUsed(key)) {

model.addAttribute("emptyFieldMessage", referenceService.getErrorMessages(reference.getEmptyMandatoryFields()));
model.addAttribute("keyUsed", referenceService.keyNotUniqueErrorMessage(key));
model.addAttribute("emptyFields", reference.getEmptyMandatoryFields());
model.addAttribute("reference", reference);

model.addAttribute("mandatoryFields", reference.getMandatoryFields());
model.addAttribute("optionalFields", reference.getOptionalFields());
model.addAttribute("fields", reference.getFields());

return "references/reference_new";
}
referenceService.saveReference(reference);
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/ohtuhatut/repository/ReferenceRepository.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

package ohtuhatut.repository;

import java.util.List;
import ohtuhatut.domain.Reference;
import org.springframework.data.jpa.repository.JpaRepository;

Expand All @@ -10,5 +11,5 @@
* @author tuomokar
*/
public interface ReferenceRepository extends JpaRepository<Reference, Long> {

List<Reference> findByKey(String key);
}
70 changes: 70 additions & 0 deletions src/main/java/ohtuhatut/service/ReferenceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,75 @@ public boolean typeIsNotKnown(String type) {
return allTypes.get(type) == null;
}

public boolean referenceKeyAlreadyUsed(String key) {
return !referenceRepository.findByKey(key).isEmpty();
}

/**
* Returns an error message if key has already been used. If the key hasn't
* been used, then null is returned.
*
* @param key A reference's Bibtex key
* @return error message if key has been used, or null if it has not been
* used
*/
public String keyNotUniqueErrorMessage(String key) {
if (referenceKeyAlreadyUsed(key)) {
return "That key has already been used, please use another key";
}
return null;
}

/**
* Returns an error message if a given reference's key is in use on some
* other reference. If it is not, then null is returned
*
* @param reference a reference to be compared to
* @return error message if key has been used on some other reference, or
* null if it has not been used
*/
public String keyIsInUseOnSomeOtherReferenceErrorMessage(Reference reference) {
if (referenceKeyAlreadyUsedOnSomeOtherReference(reference)) {
return "That key is in use on another reference, please use another key";
}
return null;
}

/**
* Checks if a key has already been used, and if it has, checks if the
* reference having that key is the same reference as the one given as the
* parameter. This method can be used for editing references - if the
* reference is the same one, then it must be able to be resaved with the
* key it already has, and the check must be applied only to other
* references.
*
* @param reference Reference to be compared to the ones in the database
* @return true if reference's key has been used on some other reference
* than the one received as the parameter. Otherwise false is returned.
*/
public boolean referenceKeyAlreadyUsedOnSomeOtherReference(Reference reference) {
List<Reference> references = referenceRepository.findByKey(reference.getKey());

for (Reference ref : references) {
if (referencesAreTheSame(ref, reference)) {
continue;
}

if (keysAreTheSame(ref.getKey(), reference.getKey())) {
return true;
}
}

return false;
}

private boolean referencesAreTheSame(Reference ref1, Reference ref2) {
return ref1.getId().equals(ref2.getId());
}

private boolean keysAreTheSame(String key1, String key2) {
return key1.equals(key2);
}


}
6 changes: 5 additions & 1 deletion src/main/resources/templates/references/reference_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ <h1 th:text="'Edit reference: ' + ${reference.title}"></h1>
<div class="alert alert-danger" th:if="${emptyFieldMessage != null}">
<p th:text="${emptyFieldMessage}"></p>
</div>

<div th:if="${keyUsed}" class="alert alert-danger">
<p th:text="${keyUsed}"></p>
</div>

<form class="form-horizontal" action="#" th:action="@{/references/{id}/edit/(id=${reference.id})}" th:object="${reference}" method="post">
<div class="form-group">
<label for="key" class="col-sm-2 control-label">*Key:</label>
<div class="col-sm-10" th:classappend="${emptyFields.contains('key')} ? 'has-error'">
<div class="col-sm-10" th:classappend="${emptyFields.contains('key')} or ${keyUsed} ? 'has-error'">
<input class="form-control" type="text" id="key" name="key" th:value="${reference.key != null} ? ${reference.key} : ''"/>
</div>
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/main/resources/templates/references/reference_new.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ <h1>Create a new reference</h1>
<div th:if="${emptyFieldMessage}" class="alert alert-danger">
<p th:text="${emptyFieldMessage}"></p>
</div>

<div th:if="${keyUsed}" class="alert alert-danger">
<p th:text="${keyUsed}"></p>
</div>

<form class="form-horizontal" action="#" th:action="@{/references/new/}" th:object="${reference}" method="post">
<div class="form-group">
<label for="key" class="col-sm-2 control-label">*Key:</label>
<div class="col-sm-10" th:classappend="${emptyFields.contains('key')} ? 'has-error'">
<div class="col-sm-10" th:classappend="${emptyFields.contains('key')} or ${keyUsed} ? 'has-error'">
<input class="form-control" id="key" name="key"/>
</div>
</div>
Expand Down
30 changes: 24 additions & 6 deletions src/test/java/ohtuhatut/selenium/ReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,22 @@ public void tryingToEnterTheReferenceCreationPageWhenGivingATypeThatNoReferenceH
assertTrue(pageSource().contains("Please choose a type first"));
}

/*
if (type == null || referenceService.typeIsNotKnown(type)) {
redirectAttr.addFlashAttribute("typeNotChosen", "Please choose a type first");
return "redirect:/references/choose";
}
*/
@Test
public void tryingToGiveAKeyThatHasAlreadyBeenUsedGivesErrorMessage() {
createAReference(3);
createAReference(3);

assertTrue(pageSource().contains("That key has already been used, please use another key"));
}

@Test
public void tryingToGiveAnAlreadyUsedKeyAndLeavingMandatoryFieldsEmptyGivesErrorMessagesForBoth() {
createAReference(3);
tryToCreateReferenceWithoutTitle(3);

assertTrue(pageSource().contains("That key has already been used, please use another key"));
assertTrue(pageSource().contains("title is empty"));
}

private void createAReference(int i) {
getToManualReferenceCreationPage();
Expand All @@ -237,6 +247,13 @@ private void createAReference(int i) {
fill("#key").with("key" + i);
submit(find("form").first());
}

private void tryToCreateReferenceWithoutTitle(int i) {
getToManualReferenceCreationPage();

fill("#key").with("key" + i);
submit(find("form").first());
}

private void getToReferencesPage() {
goTo(getUrl());
Expand Down Expand Up @@ -272,4 +289,5 @@ private void getToInproceedingsReferenceCreationPage() {
getToReferenceCreationsChoosingPage();
click(find("a", withText("Inproceedings reference")));
}

}
93 changes: 93 additions & 0 deletions src/test/java/ohtuhatut/service/ReferenceServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,98 @@ public void theMethodTypeIsNotKnownReturnsFalseWhenGivingTheTypeOfABookletRefere
public void theMethodTypeIsNotKnownReturnsFalseWhenGivingTheTypeOfAnArticleReference() {
assertFalse(referenceService.typeIsNotKnown("article"));
}

@Test
public void tryingToFindAReferenceByKeyThatIsAlreadyUsedReturnsTrue() {
Reference ref = new Reference();
ref.setKey("key1");

referenceService.saveReference(ref);

assertTrue(referenceService.referenceKeyAlreadyUsed(ref.getKey()));
}

@Test
public void tryingToFindByReferenceByKeyThatHasNotBeenUsedReturnsFalse() {
assertFalse(referenceService.referenceKeyAlreadyUsed("keyNotUsed"));
}

@Test
public void errorMessageIsReturnedCorrectlyWhenKeyHasBeenUsed() {
Reference ref = new Reference();
ref.setKey("key2");

referenceService.saveReference(ref);

assertEquals("That key has already been used, please use another key",
referenceService.keyNotUniqueErrorMessage(ref.getKey()));
}

@Test
public void errorMessageIsReturnedCorrectlyWhenKeyHasNotBeenUsed() {
assertNull(referenceService.keyNotUniqueErrorMessage("keyNotUsed"));
}

@Test
public void tryingToFindByReferenceKeyUsedOnSomeOtherReferenceReturnsTrue() {
Reference ref1 = new Reference();
ref1.setKey("key3");
Reference ref2 = new Reference();
ref2.setKey("key4");

referenceService.saveReference(ref1);
referenceService.saveReference(ref2);

ref2.setKey("key3");

assertTrue(referenceService.referenceKeyAlreadyUsedOnSomeOtherReference(ref2));
}

@Test
public void tryingToFindByReferenceKeyThatIsNotUsedOnAnyOtherReferenceReturnsFalse() {
Reference ref1 = new Reference();
ref1.setKey("key5");
Reference ref2 = new Reference();
ref2.setKey("key6");

referenceService.saveReference(ref1);
referenceService.saveReference(ref2);

assertFalse(referenceService.referenceKeyAlreadyUsedOnSomeOtherReference(ref2));
}

@Test
public void seeingIfAnyOtherReferenceHasTheSameKeyReturnsFalseWhenThereAreNoOtherReferences() {
Reference ref = new Reference();
ref.setKey("key7");

referenceService.saveReference(ref);

assertFalse(referenceService.referenceKeyAlreadyUsedOnSomeOtherReference(ref));
}

@Test
public void whenKeyIsInUseBySomeOtherReferenceTheErrorMessageIsReturned() {
Reference ref = new Reference();
ref.setKey("key8");

referenceService.saveReference(ref);

Reference ref2 = new Reference();
ref2.setKey("key8");

assertEquals("That key is in use on another reference, please use another key",
referenceService.keyIsInUseOnSomeOtherReferenceErrorMessage(ref2));
}

@Test
public void whenKeyIsNotInUseByAnyOtherReferenceNullIsReturned() {
Reference ref = new Reference();
ref.setKey("key9");

referenceService.saveReference(ref);

assertNull(referenceService.keyIsInUseOnSomeOtherReferenceErrorMessage(ref));
}

}

0 comments on commit 76b5821

Please sign in to comment.