Skip to content

Commit 1eae881

Browse files
authored
Merge pull request nus-cs2103-AY2324S1#110 from garylow2001/meeting-times
Add command to delete meeting time from clients and leads
2 parents 6cf4dd3 + da97802 commit 1eae881

File tree

9 files changed

+366
-5
lines changed

9 files changed

+366
-5
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package seedu.address.logic.commands;
2+
3+
import static java.util.Objects.requireNonNull;
4+
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
5+
6+
import java.util.List;
7+
import java.util.Optional;
8+
9+
import seedu.address.commons.core.index.Index;
10+
import seedu.address.commons.util.ToStringBuilder;
11+
import seedu.address.logic.Messages;
12+
import seedu.address.logic.commands.exceptions.CommandException;
13+
import seedu.address.model.Model;
14+
import seedu.address.model.person.Client;
15+
import seedu.address.model.person.Lead;
16+
import seedu.address.model.person.Person;
17+
18+
/**
19+
* Deletes a meeting identified using it's displayed index from the address book.
20+
*/
21+
public class DeleteMeetingCommand extends Command {
22+
23+
public static final String COMMAND_WORD = "deletemeeting";
24+
25+
public static final String MESSAGE_USAGE = COMMAND_WORD
26+
+ ": Deletes the meeting identified by the index number used in the displayed meeting list.\n"
27+
+ "Parameters: INDEX (must be a positive integer)\n"
28+
+ "Example: " + COMMAND_WORD + " 1";
29+
30+
public static final String MESSAGE_DELETE_MEETING_SUCCESS = "Deleted Meeting: %1$s from Person %2$s";
31+
32+
private final Index targetIndex;
33+
34+
public DeleteMeetingCommand(Index targetIndex) {
35+
this.targetIndex = targetIndex;
36+
}
37+
38+
/**
39+
* Deletes the meeting from the person.
40+
* @param personToDeleteMeeting Person to delete meeting from.
41+
* @return Person with meeting deleted.
42+
*/
43+
private static Person deleteMeeting(Person personToDeleteMeeting) {
44+
requireNonNull(personToDeleteMeeting);
45+
assert personToDeleteMeeting.isLead() || personToDeleteMeeting.isClient();
46+
47+
if (personToDeleteMeeting.getMeetingTime().isEmpty()) {
48+
return personToDeleteMeeting;
49+
}
50+
51+
Person personWithMeetingDeleted;
52+
53+
if (personToDeleteMeeting.isClient()) {
54+
personWithMeetingDeleted = new Client(
55+
personToDeleteMeeting.getName(),
56+
personToDeleteMeeting.getPhone(),
57+
personToDeleteMeeting.getEmail(),
58+
personToDeleteMeeting.getAddress(),
59+
Optional.empty(),
60+
personToDeleteMeeting.getTags());
61+
} else {
62+
// If person is not Client, person is a Lead
63+
assert personToDeleteMeeting.isLead();
64+
Lead leadWithMeetingDeleted = (Lead) personToDeleteMeeting;
65+
personWithMeetingDeleted = new Lead(
66+
leadWithMeetingDeleted.getName(),
67+
leadWithMeetingDeleted.getPhone(),
68+
leadWithMeetingDeleted.getEmail(),
69+
leadWithMeetingDeleted.getAddress(),
70+
leadWithMeetingDeleted.getKeyMilestone(),
71+
Optional.empty(),
72+
leadWithMeetingDeleted.getTags());
73+
}
74+
75+
return personWithMeetingDeleted;
76+
}
77+
78+
@Override
79+
public CommandResult execute(Model model) throws CommandException {
80+
requireNonNull(model);
81+
List<Person> lastShownList = model.getFilteredPersonList();
82+
83+
if (targetIndex.getZeroBased() >= lastShownList.size()) {
84+
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
85+
}
86+
87+
Person personToDeleteMeeting = lastShownList.get(targetIndex.getZeroBased());
88+
Person personWithMeetingDeleted = deleteMeeting(personToDeleteMeeting);
89+
model.setPerson(personToDeleteMeeting, personWithMeetingDeleted);
90+
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
91+
return new CommandResult(String.format(MESSAGE_DELETE_MEETING_SUCCESS,
92+
personToDeleteMeeting.getMeetingTimeString(),
93+
targetIndex.getOneBased()));
94+
}
95+
96+
@Override
97+
public boolean equals(Object other) {
98+
if (other == this) {
99+
return true;
100+
}
101+
102+
// instanceof handles nulls
103+
if (!(other instanceof DeleteMeetingCommand)) {
104+
return false;
105+
}
106+
107+
DeleteMeetingCommand otherDeleteMeetingCommand = (DeleteMeetingCommand) other;
108+
return targetIndex.equals(otherDeleteMeetingCommand.targetIndex);
109+
}
110+
111+
@Override
112+
public String toString() {
113+
return new ToStringBuilder(this)
114+
.add("targetIndex", targetIndex)
115+
.toString();
116+
}
117+
}

src/main/java/seedu/address/logic/parser/AddressBookParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import seedu.address.logic.commands.ConvertClientToLeadCommand;
1616
import seedu.address.logic.commands.ConvertLeadToClientCommand;
1717
import seedu.address.logic.commands.DeleteCommand;
18+
import seedu.address.logic.commands.DeleteMeetingCommand;
1819
import seedu.address.logic.commands.EditCommand;
1920
import seedu.address.logic.commands.ExitCommand;
2021
import seedu.address.logic.commands.FindCommand;
@@ -71,6 +72,9 @@ public Command parseCommand(String userInput) throws ParseException {
7172
case DeleteCommand.COMMAND_WORD:
7273
return new DeleteCommandParser().parse(arguments);
7374

75+
case DeleteMeetingCommand.COMMAND_WORD:
76+
return new DeleteMeetingCommandParser().parse(arguments);
77+
7478
case ClearCommand.COMMAND_WORD:
7579
return new ClearCommand();
7680

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package seedu.address.logic.parser;
2+
3+
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
4+
5+
import seedu.address.commons.core.index.Index;
6+
import seedu.address.logic.commands.DeleteMeetingCommand;
7+
import seedu.address.logic.parser.exceptions.ParseException;
8+
9+
/**
10+
* Parses input arguments and creates a new DeleteMeetingCommand object
11+
*/
12+
public class DeleteMeetingCommandParser implements Parser<DeleteMeetingCommand> {
13+
14+
/**
15+
* Parses the given {@code String} of arguments in the context of the DeleteMeetingCommand
16+
* and returns a DeleteMeetingCommand object for execution.
17+
* @throws ParseException if the user input does not conform the expected format
18+
*/
19+
@Override
20+
public DeleteMeetingCommand parse(String args) throws ParseException {
21+
try {
22+
Index index = ParserUtil.parseIndex(args);
23+
return new DeleteMeetingCommand(index);
24+
} catch (ParseException pe) {
25+
throw new ParseException(
26+
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteMeetingCommand.MESSAGE_USAGE), pe);
27+
}
28+
}
29+
}

src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"type": "client",
88
"address" : "123, Jurong West Ave 6, #08-111",
99
"keyMilestone": null,
10-
"meetingTime" : null,
10+
"meetingTime" : "12/12/2023 12:00",
1111
"tags" : [ "friends" ]
1212
}, {
1313
"name" : "Benson Meier",
@@ -43,7 +43,7 @@
4343
"type": "lead",
4444
"keyMilestone": "01/12/2023",
4545
"address" : "michegan ave",
46-
"meetingTime" : null,
46+
"meetingTime" : "12/12/2023 12:00",
4747
"tags" : []
4848
}, {
4949
"name" : "Fiona Kunz",
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package seedu.address.logic.commands;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
import static org.junit.jupiter.api.Assertions.fail;
7+
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
8+
import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
9+
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
10+
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
11+
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
12+
13+
import org.junit.jupiter.api.Test;
14+
15+
import seedu.address.commons.core.index.Index;
16+
import seedu.address.logic.Messages;
17+
import seedu.address.model.Model;
18+
import seedu.address.model.ModelManager;
19+
import seedu.address.model.UserPrefs;
20+
import seedu.address.model.person.Person;
21+
import seedu.address.testutil.PersonBuilder;
22+
23+
/**
24+
* Contains integration tests (interaction with the Model) and unit tests for
25+
* {@code DeleteMeetingCommand}.
26+
*/
27+
public class DeleteMeetingCommandTest {
28+
29+
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
30+
31+
@Test
32+
public void execute_validIndexUnfilteredList_success() {
33+
Person personToDeleteMeeting = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
34+
Person personWithMeetingDeleted = new PersonBuilder(personToDeleteMeeting)
35+
.withMeetingTime(null).buildClient(); // First person in typical address book without meeting time
36+
37+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(INDEX_FIRST_PERSON);
38+
39+
String expectedMessage = String.format(DeleteMeetingCommand.MESSAGE_DELETE_MEETING_SUCCESS,
40+
personToDeleteMeeting.getMeetingTimeString(), INDEX_FIRST_PERSON.getOneBased());
41+
42+
ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
43+
expectedModel.setPerson(personToDeleteMeeting, personWithMeetingDeleted);
44+
45+
assertCommandSuccess(deleteMeetingCommand, model, expectedMessage, expectedModel);
46+
}
47+
48+
@Test
49+
public void execute_invalidIndexUnfilteredList_throwsCommandException() {
50+
Index outOfBoundIndex = Index.fromOneBased(
51+
model.getFilteredPersonList().size() + 1); // Last person in typical address book
52+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(outOfBoundIndex);
53+
54+
CommandTestUtil.assertCommandFailure(deleteMeetingCommand, model,
55+
Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
56+
}
57+
58+
@Test
59+
public void execute_validIndexFilteredList_success() {
60+
showPersonAtIndex(model, INDEX_FIRST_PERSON);
61+
62+
Person personToDeleteMeeting = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
63+
Person personWithMeetingDeleted = new PersonBuilder(personToDeleteMeeting)
64+
.withMeetingTime(null).buildClient(); // First person in typical address book without meeting time
65+
66+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(INDEX_FIRST_PERSON);
67+
68+
String expectedMessage = String.format(DeleteMeetingCommand.MESSAGE_DELETE_MEETING_SUCCESS,
69+
personToDeleteMeeting.getMeetingTimeString(), INDEX_FIRST_PERSON.getOneBased());
70+
71+
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
72+
expectedModel.setPerson(personToDeleteMeeting, personWithMeetingDeleted);
73+
74+
assertCommandSuccess(deleteMeetingCommand, model, expectedMessage, expectedModel);
75+
}
76+
77+
@Test
78+
public void execute_invalidIndexFilteredList_throwsCommandException() {
79+
showPersonAtIndex(model, INDEX_FIRST_PERSON);
80+
81+
Index outOfBoundIndex = INDEX_SECOND_PERSON; // Second person in typical address book
82+
// ensures that outOfBoundIndex is still in bounds of address book list
83+
assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
84+
85+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(outOfBoundIndex);
86+
87+
CommandTestUtil.assertCommandFailure(deleteMeetingCommand, model,
88+
Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
89+
}
90+
91+
@Test
92+
public void deleteMeeting_personIsLead() {
93+
Index indexFirstLead = Index.fromOneBased(5);
94+
Person leadToDeleteMeeting = model.getFilteredPersonList().get(indexFirstLead.getZeroBased());
95+
assertTrue(leadToDeleteMeeting.isLead());
96+
97+
Person leadWithMeetingDeleted = new PersonBuilder(leadToDeleteMeeting)
98+
.withMeetingTime(null).buildLead(); // First lead in typical address book without meeting time
99+
100+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(indexFirstLead);
101+
102+
try {
103+
deleteMeetingCommand.execute(model);
104+
} catch (Exception e) {
105+
fail();
106+
}
107+
108+
Person expectedLead = model.getFilteredPersonList().get(indexFirstLead.getZeroBased());
109+
110+
assertTrue(expectedLead.isLead());
111+
assertEquals(expectedLead, leadWithMeetingDeleted);
112+
}
113+
114+
@Test
115+
public void deleteMeeting_personNoMeetingTime_returnsPerson() {
116+
Index indexPersonWithNoMeeting = Index.fromOneBased(3); // Third person in typical address book
117+
Person personToDeleteMeeting = model.getFilteredPersonList()
118+
.get(indexPersonWithNoMeeting.getZeroBased());
119+
120+
assertTrue(personToDeleteMeeting.getMeetingTime().isEmpty());
121+
122+
Person personWithMeetingDeleted = new PersonBuilder(personToDeleteMeeting)
123+
.withMeetingTime(null).buildClient();
124+
assertEquals(personToDeleteMeeting, personWithMeetingDeleted);
125+
126+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(indexPersonWithNoMeeting);
127+
128+
try {
129+
deleteMeetingCommand.execute(model);
130+
} catch (Exception e) {
131+
fail();
132+
}
133+
134+
Person expectedPerson = model.getFilteredPersonList().get(indexPersonWithNoMeeting.getZeroBased());
135+
assertEquals(expectedPerson, personWithMeetingDeleted);
136+
}
137+
138+
@Test
139+
public void equals() {
140+
DeleteMeetingCommand deleteMeetingFirstCommand = new DeleteMeetingCommand(INDEX_FIRST_PERSON);
141+
DeleteMeetingCommand deleteMeetingSecondCommand = new DeleteMeetingCommand(INDEX_SECOND_PERSON);
142+
143+
// same object -> returns true
144+
assertTrue(deleteMeetingFirstCommand.equals(deleteMeetingFirstCommand));
145+
146+
// same values -> returns true
147+
DeleteMeetingCommand deleteMeetingFirstCommandCopy = new DeleteMeetingCommand(INDEX_FIRST_PERSON);
148+
assertTrue(deleteMeetingFirstCommand.equals(deleteMeetingFirstCommandCopy));
149+
150+
// different types -> returns false
151+
assertFalse(deleteMeetingFirstCommand.equals(1));
152+
153+
// null -> returns false
154+
assertFalse(deleteMeetingFirstCommand.equals(null));
155+
156+
// different person -> returns false
157+
assertFalse(deleteMeetingFirstCommand.equals(deleteMeetingSecondCommand));
158+
}
159+
160+
@Test
161+
public void toStringMethod() {
162+
Index targetIndex = Index.fromOneBased(1);
163+
DeleteMeetingCommand deleteMeetingCommand = new DeleteMeetingCommand(targetIndex);
164+
String expectedString = DeleteMeetingCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
165+
assertTrue(deleteMeetingCommand.toString().equals(expectedString));
166+
}
167+
}

src/test/java/seedu/address/logic/commands/EditCommandTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.junit.jupiter.api.Assertions.assertTrue;
66
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
77
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
8+
import static seedu.address.logic.commands.CommandTestUtil.VALID_MEETING_TIME_AMY;
89
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
910
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
1011
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
@@ -37,7 +38,7 @@ public class EditCommandTest {
3738

3839
@Test
3940
public void execute_allFieldsSpecifiedUnfilteredList_success() {
40-
Person editedPerson = new PersonBuilder().buildClient();
41+
Person editedPerson = new PersonBuilder().withMeetingTime(VALID_MEETING_TIME_AMY).buildClient();
4142
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
4243
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
4344

src/test/java/seedu/address/logic/parser/AddressBookParserTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import seedu.address.logic.commands.AddLeadCommand;
2121
import seedu.address.logic.commands.ClearCommand;
2222
import seedu.address.logic.commands.DeleteCommand;
23+
import seedu.address.logic.commands.DeleteMeetingCommand;
2324
import seedu.address.logic.commands.EditCommand;
2425
import seedu.address.logic.commands.EditCommand.EditLeadDescriptor;
2526
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
@@ -74,6 +75,14 @@ public void parseCommand_delete() throws Exception {
7475
assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
7576
}
7677
//todo: test failed maybe because meeting time is null, should be fixed after merging master
78+
79+
@Test
80+
public void parseCommand_deleteMeeting() throws Exception {
81+
DeleteMeetingCommand command = (DeleteMeetingCommand) parser.parseCommand(
82+
DeleteMeetingCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
83+
assertEquals(new DeleteMeetingCommand(INDEX_FIRST_PERSON), command);
84+
}
85+
7786
@Test
7887
public void parseCommand_edit_withClient() throws Exception {
7988
Client client = new PersonBuilder().buildClient();

0 commit comments

Comments
 (0)