Skip to content

Commit

Permalink
Merge 6a8a803 into 69d0feb
Browse files Browse the repository at this point in the history
  • Loading branch information
daekoon committed Oct 28, 2019
2 parents 69d0feb + 6a8a803 commit d76160d
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 71 deletions.
2 changes: 1 addition & 1 deletion docs/DeveloperGuide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ All `Activity` models are stored inside `ActivityBook`.

When creating an activity, the title must be specified. It is optional to include participants, as they can be invited separately.

Adding of participant relies on keyword-based search. A set of keyword is passed in for each participant to be invited in. The keywords are used to search the AddressBook for a matching person. The person is added in as a participant only if there is one exact match. Otherwise, a warning message will be displayed and no participant will be added for this set of keywords.
Adding of participant uses both exact-match and keyword-based search. First, the search term passed in is used to find an contact with an exact matching name. If no exact match is found, the search term is split into keywords via whitespace. Obtained keywords are then used to search the AddressBook for a matching person. The person is added in as a participant only if there is one exact match. Otherwise, a warning message will be displayed and no participant will be added for this set of keywords.

Given below is an example usage scenario and how the create activity mechanism behaves at each step.

Expand Down
3 changes: 2 additions & 1 deletion docs/UserGuide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ Creates a new activity with a title, contacts (optional) and no expenses.
****
* The user creating the activity will be included automatically.
* Additional contacts to add to the activity can be specified by using `p/` prefix.
** Keyword matching is used to find contacts to add to the activity. Refer to <<Finding contacts or activities: `find`>> for more details.
** Initially, the application will search for contact with exact matching name.
** If no exact match is found, keyword matching is used instead. Refer to <<Finding contacts or activities: `find`>> for more details.
** For a contact to be successfully added, given keywords must have exact 1 matching contact. Otherwise, the activity will be created without adding the contact suggested by the keywords, and warning message will be shown.
* Changes the current view to this activity (as if `view a/ACTIVITY_ID` was called).
* Each activity will be assigned an activity ID automatically. +
Expand Down
26 changes: 17 additions & 9 deletions src/main/java/seedu/address/logic/commands/ActivityCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Context;
Expand Down Expand Up @@ -71,17 +72,24 @@ public CommandResult execute(Model model) throws CommandException {
// Participant will only be added if the keyword has a unique match.
for (String searchTerm : participants) {

keywords = Arrays.asList(searchTerm.split(" "));
NameContainsAllKeywordsPredicate predicate = new NameContainsAllKeywordsPredicate(keywords);
findResult = model.findPersonAll(predicate);

// Non-unique match (0 or more than 1) - this argument is skipped
if (findResult.size() != 1) {
updateWarningNotSingleMatch(warningMessage, searchTerm, findResult.size());
continue;
//Check for exact match case
Optional<Person> exactMatch = model.findPersonByName(searchTerm);
if (exactMatch.isPresent()) {
toAddPerson = exactMatch.get();
} else {

keywords = Arrays.asList(searchTerm.split(" "));
NameContainsAllKeywordsPredicate predicate = new NameContainsAllKeywordsPredicate(keywords);
findResult = model.findPersonAll(predicate);

// Non-unique match (0 or more than 1) - this argument is skipped
if (findResult.size() != 1) {
updateWarningNotSingleMatch(warningMessage, searchTerm, findResult.size());
continue;
}
toAddPerson = findResult.get(0);
}

toAddPerson = findResult.get(0);
id = toAddPerson.getPrimaryKey();

// Person already in this activity - this person is not added
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/seedu/address/logic/commands/AddCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class AddCommand extends Command {

public static final String MESSAGE_SUCCESS = "New contact added: %1$s";
public static final String MESSAGE_DUPLICATE_PERSON = "This contact already exists in the address book";
public static final String MESSAGE_DUPLICATE_NAME = "There already exists a name with the exact same name";

private final Person toAdd;

Expand All @@ -51,6 +52,9 @@ public CommandResult execute(Model model) throws CommandException {
if (model.hasPerson(toAdd)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
if (model.findPersonByName(toAdd.getName().fullName).isPresent()) {
throw new CommandException(MESSAGE_DUPLICATE_NAME);
}

model.addPerson(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/seedu/address/model/AddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javafx.collections.ObservableList;
import seedu.address.model.person.NameContainsAllKeywordsPredicate;
Expand Down Expand Up @@ -97,6 +98,18 @@ public ArrayList<Person> findPerson(NameContainsAllKeywordsPredicate predicate)
return matches;
}

/**
* Finds Person object by name, using exact match.
*/
public Optional<Person> findPersonByName(String searchTerm) {
for (Person person: persons.asUnmodifiableObservableList()) {
if (person.getName().fullName.toLowerCase().equals(searchTerm.toLowerCase())) {
return Optional.of(person);
}
}
return Optional.empty();
}

/**
* Returns true if a person with the same primary key as {@code primaryKey} exists in the address book.
*/
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;

import javafx.collections.ObservableList;
Expand Down Expand Up @@ -87,15 +88,20 @@ public interface Model {
boolean hasPerson(Person person);

/**
Finds Person objects with matching keywords, returning matches in ArrayList.
* Finds Person objects with matching keywords, returning matches in ArrayList.
*/
ArrayList<Person> findPersonAny(NameContainsKeywordsPredicate predicate);

/**
Finds Person objects with names matching all keywords, returning matches in ArrayList.
* Finds Person objects with names matching all keywords, returning matches in ArrayList.
*/
ArrayList<Person> findPersonAll(NameContainsAllKeywordsPredicate predicate);

/**
* Finds Person object that has exact matching name as the search term provided, returning an Optional of Person.
*/
Optional<Person> findPersonByName(String searchTerm);

/**
* Deletes the given person.
* The person must exist in the address book.
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.logging.Logger;

Expand Down Expand Up @@ -160,6 +161,12 @@ public ArrayList<Person> findPersonAll(NameContainsAllKeywordsPredicate predicat
return addressBook.findPerson(predicate);
}

@Override
public Optional<Person> findPersonByName(String searchTerm) {
requireNonNull(searchTerm);
return addressBook.findPersonByName(searchTerm);
}

@Override
public void deletePerson(Person target) {
addressBook.removePerson(target);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import org.junit.jupiter.api.Test;

import seedu.address.model.ActivityBook;
import seedu.address.model.Context;
import seedu.address.model.activity.Activity;
import seedu.address.model.activity.Title;
import seedu.address.model.person.NameContainsAllKeywordsPredicate;
Expand All @@ -30,9 +33,7 @@ public void constructor_nullActivity_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> new ActivityCommand(null, null));
}

/**
* TODO: put this back after abstracting out view change @Test
*/
@Test
public void execute_validActivityWithoutParticipants_addSuccessful() throws Exception {
ModelStubAcceptingActivityAdded modelStub = new ModelStubAcceptingActivityAdded();
Activity validActivity = new ActivityBuilder().build();
Expand All @@ -46,9 +47,7 @@ public void execute_validActivityWithoutParticipants_addSuccessful() throws Exce
assertEquals(Arrays.asList(validActivity), modelStub.activityList);
}

/**
* TODO: put this back after abstracting out view change @Test
*/
@Test
public void execute_validActivityWithParticipant_addSuccessful() throws Exception {
ModelStubAcceptingActivityAdded modelStub = new ModelStubAcceptingActivityAdded();
Activity validActivity = new ActivityBuilder().addPerson(TypicalPersons.ALICE).build();
Expand All @@ -64,9 +63,26 @@ public void execute_validActivityWithParticipant_addSuccessful() throws Exceptio
assertEquals(Arrays.asList(validActivity), modelStub.activityList);
}

/**
* TODO: put this back after abstracting out view change @Test
*/
@Test
public void execute_validActivityWithExactMatchParticipant_addSuccessful() throws Exception {
ModelStubAcceptingActivityAdded modelStub = new ModelStubAcceptingActivityAdded();
modelStub.addPerson(TypicalPersons.GEORGE_FIRSTNAME);
Activity validActivity = new ActivityBuilder()
.addPerson(TypicalPersons.GEORGE_FIRSTNAME).build();

ArrayList<String> searchTerms = new ArrayList<String>();
searchTerms.add("George");

CommandResult commandResult =
new ActivityCommand(new Title(ActivityBuilder.DEFAULT_TITLE), searchTerms)
.execute(modelStub);

assertEquals(String.format(ActivityCommand.MESSAGE_SUCCESS, validActivity, "George", ""),
commandResult.getFeedbackToUser());
assertEquals(Arrays.asList(validActivity), modelStub.activityList);
}

@Test
public void execute_validActivityWithInvalidParticipant_multipleMatches() throws Exception {
ModelStubAcceptingActivityAdded modelStub = new ModelStubAcceptingActivityAdded();
modelStub.addPerson(TypicalPersons.ANDY);
Expand Down Expand Up @@ -143,6 +159,17 @@ public ArrayList<Person> findPersonAll(NameContainsAllKeywordsPredicate predicat
return matches;
}

@Override
public Optional<Person> findPersonByName(String searchTerm) {
requireNonNull(searchTerm);
for (Person person : personList) {
if (person.getName().fullName.toLowerCase().equals(searchTerm.toLowerCase())) {
return Optional.of(person);
}
}
return Optional.empty();
}

@Override
public void addActivity(Activity activity) {
requireNonNull(activity);
Expand All @@ -155,6 +182,16 @@ public ActivityBook getActivityBook() {
activityBook.setActivities(activityList);
return activityBook;
}

@Override
public void setContext(Context context) {
return;
}

@Override
public void updateFilteredPersonList(Predicate<? super Person> predicate) {
return;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void setUp() {

@Test
public void execute_newPerson_success() {
Person validPerson = new PersonBuilder().build();
Person validPerson = new PersonBuilder().withName("Alice Bob").build();

Model expectedModel = new ModelManager(
model.getAddressBook(), new UserPrefs(), new InternalState(), new ActivityBook());
Expand All @@ -46,4 +46,11 @@ public void execute_duplicatePerson_throwsCommandException() {
assertCommandFailure(new AddCommand(personInList), model, AddCommand.MESSAGE_DUPLICATE_PERSON);
}

@Test
public void execute_duplicateName_throwsCommandException() {
Person personInList = model.getAddressBook().getPersonList().get(0);
Person duplicateNamePerson = new PersonBuilder().withName(personInList.getName().fullName).build();
assertCommandFailure(new AddCommand(duplicateNamePerson), model, AddCommand.MESSAGE_DUPLICATE_NAME);
}

}
44 changes: 25 additions & 19 deletions src/test/java/seedu/address/logic/commands/AddCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;

import org.junit.jupiter.api.Test;

Expand All @@ -17,6 +18,7 @@
import seedu.address.model.person.Person;
import seedu.address.stub.ModelStub;
import seedu.address.testutil.PersonBuilder;
import seedu.address.testutil.TypicalPersons;

public class AddCommandTest {

Expand All @@ -40,11 +42,22 @@ public void execute_personAcceptedByModel_addSuccessful() throws Exception {
public void execute_duplicatePerson_throwsCommandException() {
Person validPerson = new PersonBuilder().build();
AddCommand addCommand = new AddCommand(validPerson);
ModelStub modelStub = new ModelStubWithPerson(validPerson);
ModelStub modelStub = new ModelStubAcceptingPersonAdded();
modelStub.addPerson(validPerson);

assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub));
}

@Test
public void execute_duplicateName_throwsCommandException() {
Person invalidPerson = new PersonBuilder().withName("George Best").build();
AddCommand addCommand = new AddCommand(invalidPerson);
ModelStub modelStub = new ModelStubAcceptingPersonAdded();
modelStub.addPerson(TypicalPersons.GEORGE);

assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_NAME, () -> addCommand.execute(modelStub));
}

@Test
public void equals() {
Person alice = new PersonBuilder().withName("Alice").build();
Expand All @@ -69,24 +82,6 @@ public void equals() {
assertFalse(addAliceCommand.equals(addBobCommand));
}

/**
* A Model stub that contains a single person.
*/
private class ModelStubWithPerson extends ModelStub {
private final Person person;

ModelStubWithPerson(Person person) {
requireNonNull(person);
this.person = person;
}

@Override
public boolean hasPerson(Person person) {
requireNonNull(person);
return this.person.isSamePerson(person);
}
}

/**
* A Model stub that always accept the person being added.
*/
Expand All @@ -109,6 +104,17 @@ public void addPerson(Person person) {
public ReadOnlyAddressBook getAddressBook() {
return new AddressBook();
}

@Override
public Optional<Person> findPersonByName(String searchTerm) {
requireNonNull(searchTerm);
for (Person person : personsAdded) {
if (person.getName().fullName.toLowerCase().equals(searchTerm.toLowerCase())) {
return Optional.of(person);
}
}
return Optional.empty();
}
}

}

0 comments on commit d76160d

Please sign in to comment.