Skip to content

Commit

Permalink
Merge pull request #66 from Santosh3007/65-edit-task
Browse files Browse the repository at this point in the history
Add `edit_task` Command
  • Loading branch information
jasonqiu212 committed Oct 12, 2022
2 parents c0eeab8 + ec7b67f commit 7b2a5d7
Show file tree
Hide file tree
Showing 9 changed files with 612 additions and 9 deletions.
168 changes: 168 additions & 0 deletions src/main/java/swift/logic/commands/EditTaskCommand.java
@@ -0,0 +1,168 @@
package swift.logic.commands;

import static java.util.Objects.requireNonNull;
import static swift.logic.parser.CliSyntax.PREFIX_CONTACT;
import static swift.logic.parser.CliSyntax.PREFIX_NAME;
import static swift.model.Model.PREDICATE_SHOW_ALL_TASKS;

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

import swift.commons.core.Messages;
import swift.commons.core.index.Index;
import swift.commons.util.CollectionUtil;
import swift.logic.commands.exceptions.CommandException;
import swift.model.Model;
import swift.model.task.Task;
import swift.model.task.TaskName;

/**
* Edits the details of an existing task in the address book.
*/
public class EditTaskCommand extends Command {

public static final String COMMAND_WORD = "edit_task";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the task identified "
+ "by the index number used in the displayed task list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_CONTACT + "CONTACT] "
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_NAME + "Finish Assignment "
+ PREFIX_CONTACT + "2";

public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the address book.";

private final Index index;
private final EditTaskDescriptor editTaskDescriptor;

/**
* @param index of the task in the filtered task list to edit
* @param editTaskDescriptor details to edit the task with
*/
public EditTaskCommand(Index index, EditTaskDescriptor editTaskDescriptor) {
requireNonNull(index);
requireNonNull(editTaskDescriptor);

this.index = index;
this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor);
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Task> lastShownList = model.getFilteredTaskList();

if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
}

Task taskToEdit = lastShownList.get(index.getZeroBased());
Task editedTask = createEditedTask(taskToEdit, editTaskDescriptor);

if (!taskToEdit.equals(editedTask) && model.hasTask(editedTask)) {
throw new CommandException(MESSAGE_DUPLICATE_TASK);
}

model.setTask(taskToEdit, editedTask);
model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, editedTask));
}

/**
* Creates and returns a {@code Task} with the details of {@code taskToEdit}
* edited with {@code editTaskDescriptor}.
*/
private static Task createEditedTask(Task taskToEdit, EditTaskDescriptor editTaskDescriptor) {
assert taskToEdit != null;

TaskName updatedTaskName = editTaskDescriptor.getTaskName().orElse(taskToEdit.getTaskName());
Index updatedContactIndex = editTaskDescriptor.getContactIndex().orElse(taskToEdit.getContactIndex());

return new Task(updatedTaskName, updatedContactIndex);
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof EditTaskCommand)) {
return false;
}

// state check
EditTaskCommand e = (EditTaskCommand) other;
return index.equals(e.index)
&& editTaskDescriptor.equals(e.editTaskDescriptor);
}

/**
* Stores the details to edit the task with. Each non-empty field value will replace the
* corresponding field value of the task.
*/
public static class EditTaskDescriptor {
private TaskName taskName;
private Index contactIndex;

public EditTaskDescriptor() {}

/**
* Copy constructor.
* A defensive copy of {@code tags} is used internally.
*/
public EditTaskDescriptor(EditTaskDescriptor toCopy) {
setTaskName(toCopy.taskName);
setContactIndex(toCopy.contactIndex);
}

/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
return CollectionUtil.isAnyNonNull(taskName, contactIndex);
}

public void setTaskName(TaskName taskName) {
this.taskName = taskName;
}

public Optional<TaskName> getTaskName() {
return Optional.ofNullable(taskName);
}

public void setContactIndex(Index contactIndex) {
this.contactIndex = contactIndex;
}

public Optional<Index> getContactIndex() {
return Optional.ofNullable(contactIndex);
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof EditTaskDescriptor)) {
return false;
}

// state check
EditTaskDescriptor e = (EditTaskDescriptor) other;

return getTaskName().equals(e.getTaskName())
&& getContactIndex().equals(e.getContactIndex());
}
}
}
3 changes: 3 additions & 0 deletions src/main/java/swift/logic/parser/AddressBookParser.java
Expand Up @@ -13,6 +13,7 @@
import swift.logic.commands.DeleteCommand;
import swift.logic.commands.DeleteTaskCommand;
import swift.logic.commands.EditContactCommand;
import swift.logic.commands.EditTaskCommand;
import swift.logic.commands.ExitCommand;
import swift.logic.commands.FindContactCommand;
import swift.logic.commands.FindTaskCommand;
Expand Down Expand Up @@ -64,6 +65,8 @@ public Command parseCommand(String userInput) throws ParseException {
return new ListTaskCommand();
case AddTaskCommand.COMMAND_WORD:
return new AddTaskCommandParser().parse(arguments);
case EditTaskCommand.COMMAND_WORD:
return new EditTaskCommandParser().parse(arguments);
case DeleteTaskCommand.COMMAND_WORD:
return new DeleteTaskCommandParser().parse(arguments);
case FindTaskCommand.COMMAND_WORD:
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/swift/logic/parser/EditTaskCommandParser.java
@@ -0,0 +1,51 @@
package swift.logic.parser;

import static java.util.Objects.requireNonNull;
import static swift.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static swift.logic.parser.CliSyntax.PREFIX_CONTACT;
import static swift.logic.parser.CliSyntax.PREFIX_NAME;

import swift.commons.core.index.Index;
import swift.logic.commands.EditTaskCommand;
import swift.logic.commands.EditTaskCommand.EditTaskDescriptor;
import swift.logic.parser.exceptions.ParseException;

/**
* Parses input arguments and creates a new EditTaskCommand object
*/
public class EditTaskCommandParser implements Parser<EditTaskCommand> {

/**
* Parses the given {@code String} of arguments in the context of the EditTaskCommand
* and returns an EditTaskCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public EditTaskCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_CONTACT);

Index index;

try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditTaskCommand.MESSAGE_USAGE), pe);
}

EditTaskDescriptor editTaskDescriptor = new EditTaskDescriptor();
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
editTaskDescriptor.setTaskName(ParserUtil.parseTaskName(argMultimap.getValue(PREFIX_NAME).get()));
}
if (argMultimap.getValue(PREFIX_CONTACT).isPresent()) {
editTaskDescriptor.setContactIndex(ParserUtil.parseIndex(argMultimap.getValue(PREFIX_CONTACT).get()));
}

if (!editTaskDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditTaskCommand.MESSAGE_NOT_EDITED);
}

return new EditTaskCommand(index, editTaskDescriptor);
}

}
4 changes: 4 additions & 0 deletions src/main/java/swift/model/task/Task.java
Expand Up @@ -28,6 +28,10 @@ public TaskName getTaskName() {
return taskName;
}

public Index getContactIndex() {
return contactIndex;
}

@Override
public boolean equals(Object other) {
return other == this
Expand Down
33 changes: 25 additions & 8 deletions src/test/java/swift/logic/commands/CommandTestUtil.java
Expand Up @@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static swift.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static swift.logic.parser.CliSyntax.PREFIX_CONTACT;
import static swift.logic.parser.CliSyntax.PREFIX_EMAIL;
import static swift.logic.parser.CliSyntax.PREFIX_NAME;
import static swift.logic.parser.CliSyntax.PREFIX_PHONE;
Expand All @@ -22,6 +23,7 @@
import swift.model.person.PersonNameContainsKeywordsPredicate;
import swift.model.task.Task;
import swift.testutil.EditPersonDescriptorBuilder;
import swift.testutil.EditTaskDescriptorBuilder;

/**
* Contains helper methods for testing commands.
Expand All @@ -38,6 +40,8 @@ public class CommandTestUtil {
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
public static final String VALID_TAG_HUSBAND = "husband";
public static final String VALID_TAG_FRIEND = "friend";
public static final int VALID_CONTACT_INDEX = 0;
public static final int VALID_CONTACT_ONE_BASED_INDEX = 1;

public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
Expand All @@ -49,29 +53,40 @@ public class CommandTestUtil {
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
public static final String CONTACT_INDEX_TASK1 = " " + PREFIX_CONTACT + VALID_CONTACT_ONE_BASED_INDEX;

public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
public static final String INVALID_CONTACT_INDEX = " " + PREFIX_CONTACT + "a"; // 'a' not allowed in index

public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";

public static final EditContactCommand.EditPersonDescriptor DESC_AMY;
public static final EditContactCommand.EditPersonDescriptor DESC_BOB;

static {
DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
.withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
.withTags(VALID_TAG_FRIEND).build();
DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
.withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
}

public static final String VALID_TASK_NAME_1 = "CS2103T";
public static final String VALID_TASK_NAME_2 = "Buy Milk";
public static final String VALID_TASK_NAME_3 = "Finish Assignment";

public static final EditTaskCommand.EditTaskDescriptor DESC_TASK_1;
public static final EditTaskCommand.EditTaskDescriptor DESC_TASK_2;

static {
DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
.withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
.withTags(VALID_TAG_FRIEND).build();
DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
.withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
DESC_TASK_1 = new EditTaskDescriptorBuilder().withName(VALID_TASK_NAME_1).build();
DESC_TASK_2 = new EditTaskDescriptorBuilder().withName(VALID_TASK_NAME_2).build();
}

/**
Expand Down Expand Up @@ -110,11 +125,13 @@ public static void assertCommandFailure(Command command, Model actualModel, Stri
// we are unable to defensively copy the model for comparison later, so we can
// only do so by copying its components.
AddressBook expectedAddressBook = new AddressBook(actualModel.getAddressBook());
List<Person> expectedFilteredList = new ArrayList<>(actualModel.getFilteredPersonList());
List<Person> expectedFilteredPersonList = new ArrayList<>(actualModel.getFilteredPersonList());
List<Task> expectedFilteredTaskList = new ArrayList<>(actualModel.getFilteredTaskList());

assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel));
assertEquals(expectedAddressBook, actualModel.getAddressBook());
assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
assertEquals(expectedFilteredPersonList, actualModel.getFilteredPersonList());
assertEquals(expectedFilteredTaskList, actualModel.getFilteredTaskList());
}
/**
* Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
Expand Down

0 comments on commit 7b2a5d7

Please sign in to comment.