From 444135e1bdd0fb5ca67296e2fcba062bb01c56a1 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Fri, 11 Oct 2024 04:40:13 +0800 Subject: [PATCH 01/17] Add Mark VIP Command There does not exist a command to label a customer as a VIP. Let's add the class representing such a command, and the required fields in the Person class. --- .../logic/commands/MarkVipCommand.java | 77 +++++++++++++++++++ src/main/java/seedu/address/model/Model.java | 11 +++ .../seedu/address/model/ModelManager.java | 9 +++ .../seedu/address/model/person/Person.java | 17 +++- .../logic/commands/AddCommandTest.java | 5 ++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/main/java/seedu/address/logic/commands/MarkVipCommand.java diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java new file mode 100644 index 00000000000..2c4e878acb4 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -0,0 +1,77 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Person; + +public class MarkVipCommand extends Command { + + public static final String COMMAND_WORD = "vip"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks or unmarks the person identified by the index " + + "number used in the displayed person list as a VIP.\n" + + "Parameters: INDEX (must be a positive integer) IS_VIP (must be \"true\" or \"false\")\n" + + "Example: " + COMMAND_WORD + " 1 true"; + + public static final String MESSAGE_VIP_PERSON_SUCCESS = "Person marked as a VIP: %1$s"; + public static final String MESSAGE_UNVIP_PERSON_SUCCESS = "VIP status removed from person: %1$s"; + public static final String MESSAGE_VIP_PERSON_OBSOLETE = "Person already a VIP: %1$s"; + public static final String MESSAGE_UNVIP_PERSON_OBSOLETE = "Person not a VIP: %1$s"; + private final String MESSAGE_SUCCESS; + private final String MESSAGE_OBSOLETE; + + private final Index targetIndex; + public final boolean newState; + + public MarkVipCommand(Index targetIndex, boolean newState) { + this.targetIndex = targetIndex; + this.newState = newState; + if (newState) { + MESSAGE_SUCCESS = MESSAGE_VIP_PERSON_SUCCESS; + MESSAGE_OBSOLETE = MESSAGE_VIP_PERSON_OBSOLETE; + } else { + MESSAGE_SUCCESS = MESSAGE_UNVIP_PERSON_SUCCESS; + MESSAGE_OBSOLETE = MESSAGE_UNVIP_PERSON_OBSOLETE; + } + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredPersonList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToMark = lastShownList.get(targetIndex.getZeroBased()); + boolean isSuccessful = model.markVip(personToMark, newState); + String message = MESSAGE_OBSOLETE; + if (isSuccessful) { + message = MESSAGE_SUCCESS; + } + return new CommandResult(String.format(message, Messages.format(personToMark))); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof MarkVipCommand)) { + return false; + } + + MarkVipCommand otherMarkVipCommand = (MarkVipCommand) other; + return targetIndex.equals(otherMarkVipCommand.targetIndex); + } +} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index d54df471c1f..8ddb54ab6a3 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -76,6 +76,17 @@ public interface Model { */ void setPerson(Person target, Person editedPerson); + /** + * Marks the given person {@code target} as a VIP if newVipStatus is true, + * otherwise revokes their status as VIP. + * {@code target} must exist in the address book. + * + * @param target + * @param newVipStatus + * @return + */ + boolean markVip(Person target, boolean newVipStatus); + /** Returns an unmodifiable view of the filtered person list */ ObservableList getFilteredPersonList(); diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 57bc563fde6..5a1f80cdb95 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -111,6 +111,15 @@ public void setPerson(Person target, Person editedPerson) { addressBook.setPerson(target, editedPerson); } + @Override + public boolean markVip(Person target, boolean newVipStatus) { + if (newVipStatus == target.isVip()) { + return false; + } + target.setVipStatus(newVipStatus); + return true; + } + //=========== Filtered Person List Accessors ============================================================= /** diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index abe8c46b535..a5b39e4a82e 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -24,6 +24,7 @@ public class Person { // Data fields private final Address address; private final Set tags = new HashSet<>(); + private boolean isVip; /** * Every field must be present and not null. @@ -35,6 +36,7 @@ public Person(Name name, Phone phone, Email email, Address address, Set tag this.email = email; this.address = address; this.tags.addAll(tags); + this.isVip = false; } public Name getName() { @@ -61,6 +63,15 @@ public Set getTags() { return Collections.unmodifiableSet(tags); } + public boolean isVip() { + return isVip; + } + + public void setVipStatus(boolean isVip) { + assert isVip != this.isVip; + this.isVip = isVip; + } + /** * Returns true if both persons have the same name. * This defines a weaker notion of equality between two persons. @@ -94,13 +105,14 @@ public boolean equals(Object other) { && phone.equals(otherPerson.phone) && email.equals(otherPerson.email) && address.equals(otherPerson.address) - && tags.equals(otherPerson.tags); + && tags.equals(otherPerson.tags) + && isVip == otherPerson.isVip; } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); + return Objects.hash(name, phone, email, address, tags, isVip); } @Override @@ -111,6 +123,7 @@ public String toString() { .add("email", email) .add("address", address) .add("tags", tags) + .add("isVip", isVip) .toString(); } diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index 90e8253f48e..87d8c327767 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -148,6 +148,11 @@ public void setPerson(Person target, Person editedPerson) { throw new AssertionError("This method should not be called."); } + @Override + public boolean markVip(Person target, boolean newVipStatus) { + throw new AssertionError("This method should not be called."); + } + @Override public ObservableList getFilteredPersonList() { throw new AssertionError("This method should not be called."); From 5df2303b5c22d6d9ed92eb94df842fe3dfa3fc1f Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Fri, 11 Oct 2024 10:54:48 +0800 Subject: [PATCH 02/17] Implement parser for markVip operations --- .../logic/commands/MarkVipCommand.java | 4 +- .../seedu/address/logic/parser/CliSyntax.java | 1 + .../logic/parser/MarkVipCommandParser.java | 46 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 2c4e878acb4..9aa255b5947 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -17,7 +17,7 @@ public class MarkVipCommand extends Command { public static final String MESSAGE_USAGE = COMMAND_WORD + ": Marks or unmarks the person identified by the index " + "number used in the displayed person list as a VIP.\n" - + "Parameters: INDEX (must be a positive integer) IS_VIP (must be \"true\" or \"false\")\n" + + "Parameters: INDEX (must be a positive integer) v/IS_VIP (must be \"true\" or \"false\")\n" + "Example: " + COMMAND_WORD + " 1 true"; public static final String MESSAGE_VIP_PERSON_SUCCESS = "Person marked as a VIP: %1$s"; @@ -47,6 +47,8 @@ public CommandResult execute(Model model) throws CommandException { requireNonNull(model); List lastShownList = model.getFilteredPersonList(); + System.out.println("Marking VIP: " + targetIndex + " " + newState); + if (targetIndex.getZeroBased() >= lastShownList.size()) { throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 75b1a9bf119..1ea3a3d9480 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -11,5 +11,6 @@ public class CliSyntax { public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); + public static final Prefix PREFIX_MARKVIP = new Prefix("v/"); } diff --git a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java new file mode 100644 index 00000000000..6446d902ce3 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java @@ -0,0 +1,46 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MARKVIP; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.MarkVipCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +public class MarkVipCommandParser { + + /** + * Parses the given {@code String} of arguments in the context of the MarkVipCommand + * and returns a MarkVipCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public MarkVipCommand parse(String args) throws ParseException { + requireNonNull(args); + String trimmedArgs = args.trim(); + + String[] splitArgs = trimmedArgs.split("\\s+"); + + if (splitArgs.length != 2) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE)); + } + Index index; + try { + index = ParserUtil.parseIndex(splitArgs[0]); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE), pe); + } + boolean newState; + switch (splitArgs[1]) { + case "true": + return new MarkVipCommand(index, true); + case "false": + return new MarkVipCommand(index, false); + default: + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE)); + } + } +} From 09829eb3e484a0b77eb514a5b280a3171a60abf2 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Fri, 11 Oct 2024 17:17:38 +0800 Subject: [PATCH 03/17] Add VIP field to UI and implement VIP command There is no way to update or view the VIP status of a user via the app. Let's add a label that is visible only for VIPs and implement the command "vip" --- .../address/logic/commands/MarkVipCommand.java | 2 -- .../logic/parser/AddressBookParser.java | 4 ++++ src/main/java/seedu/address/ui/PersonCard.java | 3 +++ src/main/resources/view/PersonListCard.fxml | 18 ++++++++++++++---- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 9aa255b5947..6c2e5836b21 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -47,8 +47,6 @@ public CommandResult execute(Model model) throws CommandException { requireNonNull(model); List lastShownList = model.getFilteredPersonList(); - System.out.println("Marking VIP: " + targetIndex + " " + newState); - if (targetIndex.getZeroBased() >= lastShownList.size()) { throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); } diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 3149ee07e0b..ac93fbfdf62 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -17,6 +17,7 @@ import seedu.address.logic.commands.FindCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.MarkVipCommand; import seedu.address.logic.parser.exceptions.ParseException; /** @@ -77,6 +78,9 @@ public Command parseCommand(String userInput) throws ParseException { case HelpCommand.COMMAND_WORD: return new HelpCommand(); + case MarkVipCommand.COMMAND_WORD: + return new MarkVipCommandParser().parse(arguments); + default: logger.finer("This user input caused a ParseException: " + userInput); throw new ParseException(MESSAGE_UNKNOWN_COMMAND); diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 094c42cda82..51e6e40fa3f 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -39,6 +39,8 @@ public class PersonCard extends UiPart { @FXML private Label email; @FXML + private Label vip; + @FXML private FlowPane tags; /** @@ -55,5 +57,6 @@ public PersonCard(Person person, int displayedIndex) { person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + vip.setVisible(person.isVip()); } } diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index 84e09833a87..5307bfe7140 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -7,30 +7,40 @@ + + - + - + - + - + + + From 0329030a0797df87560b1031f403a8bd24cf4e9c Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Fri, 11 Oct 2024 17:58:45 +0800 Subject: [PATCH 04/17] Restore Person's immutability and update edit's behavior Edit removes VIP status from edited persons The current implementation of VIP status makes Person no longer immutable Let's update the implementations to address these issues. --- .../address/logic/commands/EditCommand.java | 3 ++- .../logic/commands/MarkVipCommand.java | 21 ++++++++++++++----- .../logic/parser/MarkVipCommandParser.java | 1 - src/main/java/seedu/address/model/Model.java | 11 ---------- .../seedu/address/model/ModelManager.java | 9 -------- .../seedu/address/model/person/Person.java | 12 +++++------ 6 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 4b581c7331e..16714319ea0 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -100,8 +100,9 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); + boolean isVip = personToEdit.isVip(); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags, isVip); } @Override diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 6c2e5836b21..fabb1a2733b 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -3,12 +3,18 @@ import static java.util.Objects.requireNonNull; import java.util.List; +import java.util.Set; import seedu.address.commons.core.index.Index; import seedu.address.logic.Messages; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; +import seedu.address.model.person.Address; +import seedu.address.model.person.Email; +import seedu.address.model.person.Name; import seedu.address.model.person.Person; +import seedu.address.model.person.Phone; +import seedu.address.model.tag.Tag; public class MarkVipCommand extends Command { @@ -52,12 +58,17 @@ public CommandResult execute(Model model) throws CommandException { } Person personToMark = lastShownList.get(targetIndex.getZeroBased()); - boolean isSuccessful = model.markVip(personToMark, newState); - String message = MESSAGE_OBSOLETE; - if (isSuccessful) { - message = MESSAGE_SUCCESS; + if (personToMark.isVip() == newState) { + return new CommandResult(String.format(MESSAGE_OBSOLETE, Messages.format(personToMark))); } - return new CommandResult(String.format(message, Messages.format(personToMark))); + Name name = personToMark.getName(); + Address address = personToMark.getAddress(); + Email email = personToMark.getEmail(); + Phone phone = personToMark.getPhone(); + Set tags = personToMark.getTags(); + Person updatedPerson = new Person(name, phone, email, address, tags, newState); + model.setPerson(personToMark, updatedPerson); + return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(personToMark))); } @Override diff --git a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java index 6446d902ce3..5ea091199f0 100644 --- a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java @@ -32,7 +32,6 @@ public MarkVipCommand parse(String args) throws ParseException { throw new ParseException( String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE), pe); } - boolean newState; switch (splitArgs[1]) { case "true": return new MarkVipCommand(index, true); diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 8ddb54ab6a3..d54df471c1f 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -76,17 +76,6 @@ public interface Model { */ void setPerson(Person target, Person editedPerson); - /** - * Marks the given person {@code target} as a VIP if newVipStatus is true, - * otherwise revokes their status as VIP. - * {@code target} must exist in the address book. - * - * @param target - * @param newVipStatus - * @return - */ - boolean markVip(Person target, boolean newVipStatus); - /** Returns an unmodifiable view of the filtered person list */ ObservableList getFilteredPersonList(); diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 5a1f80cdb95..57bc563fde6 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -111,15 +111,6 @@ public void setPerson(Person target, Person editedPerson) { addressBook.setPerson(target, editedPerson); } - @Override - public boolean markVip(Person target, boolean newVipStatus) { - if (newVipStatus == target.isVip()) { - return false; - } - target.setVipStatus(newVipStatus); - return true; - } - //=========== Filtered Person List Accessors ============================================================= /** diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index a5b39e4a82e..4c4733df708 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -24,19 +24,22 @@ public class Person { // Data fields private final Address address; private final Set tags = new HashSet<>(); - private boolean isVip; + private final boolean isVip; /** * Every field must be present and not null. */ public Person(Name name, Phone phone, Email email, Address address, Set tags) { + this(name, phone, email, address, tags, false); + } + public Person(Name name, Phone phone, Email email, Address address, Set tags, boolean isVip) { requireAllNonNull(name, phone, email, address, tags); this.name = name; this.phone = phone; this.email = email; this.address = address; this.tags.addAll(tags); - this.isVip = false; + this.isVip = isVip; } public Name getName() { @@ -67,11 +70,6 @@ public boolean isVip() { return isVip; } - public void setVipStatus(boolean isVip) { - assert isVip != this.isVip; - this.isVip = isVip; - } - /** * Returns true if both persons have the same name. * This defines a weaker notion of equality between two persons. From c956f7ff937b29d1aaff5b6bf6220f5bf9ba0e63 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Sat, 12 Oct 2024 02:45:27 +0800 Subject: [PATCH 05/17] Resolve checkstyle issues --- .../logic/commands/MarkVipCommand.java | 26 ++++++++++++------- .../logic/parser/MarkVipCommandParser.java | 4 ++- .../seedu/address/model/person/Person.java | 4 +++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index fabb1a2733b..2be50ba7a77 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -16,6 +16,9 @@ import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +/** + * Marks a person as a VIP or revokes that title. + */ public class MarkVipCommand extends Command { public static final String COMMAND_WORD = "vip"; @@ -30,21 +33,26 @@ public class MarkVipCommand extends Command { public static final String MESSAGE_UNVIP_PERSON_SUCCESS = "VIP status removed from person: %1$s"; public static final String MESSAGE_VIP_PERSON_OBSOLETE = "Person already a VIP: %1$s"; public static final String MESSAGE_UNVIP_PERSON_OBSOLETE = "Person not a VIP: %1$s"; - private final String MESSAGE_SUCCESS; - private final String MESSAGE_OBSOLETE; + private final String messageSuccess; + private final String messageObsolete; private final Index targetIndex; - public final boolean newState; + private final boolean newState; + /** + * Creates a MarkVipCommand to mark the specified {@code Person} as a VIP + * @param targetIndex the index of the Person in the list + * @param newState whether the Person should be labelled as a VIP when the operation is complete + */ public MarkVipCommand(Index targetIndex, boolean newState) { this.targetIndex = targetIndex; this.newState = newState; if (newState) { - MESSAGE_SUCCESS = MESSAGE_VIP_PERSON_SUCCESS; - MESSAGE_OBSOLETE = MESSAGE_VIP_PERSON_OBSOLETE; + messageSuccess = MESSAGE_VIP_PERSON_SUCCESS; + messageObsolete = MESSAGE_VIP_PERSON_OBSOLETE; } else { - MESSAGE_SUCCESS = MESSAGE_UNVIP_PERSON_SUCCESS; - MESSAGE_OBSOLETE = MESSAGE_UNVIP_PERSON_OBSOLETE; + messageSuccess = MESSAGE_UNVIP_PERSON_SUCCESS; + messageObsolete = MESSAGE_UNVIP_PERSON_OBSOLETE; } } @@ -59,7 +67,7 @@ public CommandResult execute(Model model) throws CommandException { Person personToMark = lastShownList.get(targetIndex.getZeroBased()); if (personToMark.isVip() == newState) { - return new CommandResult(String.format(MESSAGE_OBSOLETE, Messages.format(personToMark))); + return new CommandResult(String.format(messageObsolete, Messages.format(personToMark))); } Name name = personToMark.getName(); Address address = personToMark.getAddress(); @@ -68,7 +76,7 @@ public CommandResult execute(Model model) throws CommandException { Set tags = personToMark.getTags(); Person updatedPerson = new Person(name, phone, email, address, tags, newState); model.setPerson(personToMark, updatedPerson); - return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(personToMark))); + return new CommandResult(String.format(messageSuccess, Messages.format(personToMark))); } @Override diff --git a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java index 5ea091199f0..57817f4c996 100644 --- a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java @@ -2,12 +2,14 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_MARKVIP; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.MarkVipCommand; import seedu.address.logic.parser.exceptions.ParseException; +/** + * Parses input arguments and creates a new MarkVipCommand. + */ public class MarkVipCommandParser { /** diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 4c4733df708..1181770458a 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -32,6 +32,10 @@ public class Person { public Person(Name name, Phone phone, Email email, Address address, Set tags) { this(name, phone, email, address, tags, false); } + + /** + * Every field must be present and not null. + */ public Person(Name name, Phone phone, Email email, Address address, Set tags, boolean isVip) { requireAllNonNull(name, phone, email, address, tags); this.name = name; From 89ee2f966e7350357dd37657776de557068ae934 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Sat, 12 Oct 2024 02:51:18 +0800 Subject: [PATCH 06/17] Remove outdated overwrite from testing code --- .../java/seedu/address/logic/commands/AddCommandTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index 87d8c327767..90e8253f48e 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -148,11 +148,6 @@ public void setPerson(Person target, Person editedPerson) { throw new AssertionError("This method should not be called."); } - @Override - public boolean markVip(Person target, boolean newVipStatus) { - throw new AssertionError("This method should not be called."); - } - @Override public ObservableList getFilteredPersonList() { throw new AssertionError("This method should not be called."); From bd07646cdf93ea76d916224709fb421ba6358bd7 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Sat, 12 Oct 2024 02:59:11 +0800 Subject: [PATCH 07/17] Update outdated test The output of Person.toString() has changed. Let's update the function testing Person.toString() to reflect the update. --- src/test/java/seedu/address/model/person/PersonTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java index 31a10d156c9..1241d255ae9 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/seedu/address/model/person/PersonTest.java @@ -93,7 +93,8 @@ public void equals() { @Test public void toStringMethod() { String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone() - + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}"; + + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + + ", isVip=" + ALICE.isVip() + "}"; assertEquals(expected, ALICE.toString()); } } From 700964596ef4a125b49264e6fd54ce7f54d72eee Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Sat, 12 Oct 2024 03:17:15 +0800 Subject: [PATCH 08/17] Fix checkstyle error Recent patch has a code style error. Let's fix it and hope I don't need anymore darn patches --- src/test/java/seedu/address/model/person/PersonTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java index 1241d255ae9..1c6709c5e12 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/seedu/address/model/person/PersonTest.java @@ -93,8 +93,8 @@ public void equals() { @Test public void toStringMethod() { String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone() - + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + - ", isVip=" + ALICE.isVip() + "}"; + + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + + ", isVip=" + ALICE.isVip() + "}"; assertEquals(expected, ALICE.toString()); } } From 90899bef36c7bfd0b320290d5ca11803c90d8c9f Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Mon, 14 Oct 2024 17:33:46 +0800 Subject: [PATCH 09/17] Update user guide to reflect VIP functionality --- docs/UserGuide.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index bceb5e3c26e..7cc9481e22b 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -172,6 +172,21 @@ If your changes to the data file makes its format invalid, AddressBook will disc Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly. +### Marking whether a person is a VIP : `vip` + +Marks the specified person from the address book as a VIP or removes said label. + +Format: `vip INDEX v/IS_VIP` + +* Affects the person at the specified `INDEX`. +* The index refers to the index number shown in the displayed person list. +* The index **must be a positive integer** 1, 2, 3, …​ +* IS_VIP should either be `true` or `false`, corresponding to whether you intend to mark the target as a VIP or remove such a mark. + +Examples: +* `list` followed by `vip 2 v/true` marks the 2nd person in the address book as a VIP. +* `find Betsy` followed by `vip 1 v/false` removes VIP status from the 1st person in the results of the `find` command. + ### Archiving data files `[coming in v2.0]` _Details coming soon ..._ @@ -202,4 +217,5 @@ Action | Format, Examples **Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`
e.g.,`edit 2 n/James Lee e/jameslee@example.com` **Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` **List** | `list` +**Vip** | `vip INDEX v/IS_VIP`
e.g., `vip 3 v/true` **Help** | `help` From 14359c0d51ef299014a551b15b79859c882d2a54 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Mon, 14 Oct 2024 18:32:06 +0800 Subject: [PATCH 10/17] Implement saving VIP states When restarting the application, customers' VIP states are not saved. Let's allow customers' VIP states to be saved and loaded. --- .../seedu/address/storage/JsonAdaptedPerson.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index bd1ca0f56c8..ffc3460f3cc 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -29,14 +29,15 @@ class JsonAdaptedPerson { private final String email; private final String address; private final List tags = new ArrayList<>(); + private final boolean isVip; /** * Constructs a {@code JsonAdaptedPerson} with the given person details. */ @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tags") List tags) { + @JsonProperty("email") String email, @JsonProperty("address") String address, + @JsonProperty("tags") List tags, @JsonProperty("isVip") boolean isVip) { this.name = name; this.phone = phone; this.email = email; @@ -44,6 +45,14 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone if (tags != null) { this.tags.addAll(tags); } + this.isVip = isVip; + } + + /** + * Constructs a {@code JsonAdaptedPerson} with the given person details, treating isVip as false. + */ + public JsonAdaptedPerson(String name, String phone, String email, String address, List tags) { + this(name, phone, email, address, tags, false); } /** @@ -57,6 +66,7 @@ public JsonAdaptedPerson(Person source) { tags.addAll(source.getTags().stream() .map(JsonAdaptedTag::new) .collect(Collectors.toList())); + isVip = source.isVip(); } /** @@ -103,7 +113,7 @@ public Person toModelType() throws IllegalValueException { final Address modelAddress = new Address(address); final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags, isVip); } } From 83826b544316ac524522d361d1071f6408254ddf Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Mon, 14 Oct 2024 18:34:38 +0800 Subject: [PATCH 11/17] Fix checkstyle error --- src/main/java/seedu/address/storage/JsonAdaptedPerson.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index ffc3460f3cc..7b851d57070 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -51,7 +51,7 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone /** * Constructs a {@code JsonAdaptedPerson} with the given person details, treating isVip as false. */ - public JsonAdaptedPerson(String name, String phone, String email, String address, List tags) { + public JsonAdaptedPerson(String name, String phone, String email, String address, List tags) { this(name, phone, email, address, tags, false); } From c3526e24569473d40d2d4866f1fb15e5211b03d6 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Wed, 16 Oct 2024 17:26:38 +0800 Subject: [PATCH 12/17] Add tests for MarkVipCommand --- .../logic/commands/MarkVipCommand.java | 3 +- .../logic/commands/MarkVipCommandTest.java | 140 ++++++++++++++++++ .../seedu/address/testutil/PersonBuilder.java | 13 +- 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 src/test/java/seedu/address/logic/commands/MarkVipCommandTest.java diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 2be50ba7a77..1f3b6ead5b5 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -1,5 +1,6 @@ package seedu.address.logic.commands; +import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; import java.util.List; @@ -91,6 +92,6 @@ public boolean equals(Object other) { } MarkVipCommand otherMarkVipCommand = (MarkVipCommand) other; - return targetIndex.equals(otherMarkVipCommand.targetIndex); + return targetIndex.equals(otherMarkVipCommand.targetIndex) && newState == otherMarkVipCommand.newState; } } diff --git a/src/test/java/seedu/address/logic/commands/MarkVipCommandTest.java b/src/test/java/seedu/address/logic/commands/MarkVipCommandTest.java new file mode 100644 index 00000000000..4cfa42c1e35 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/MarkVipCommandTest.java @@ -0,0 +1,140 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.Messages; +import seedu.address.model.AddressBook; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.Person; +import seedu.address.testutil.PersonBuilder; + +/** + * Contains integration tests (interaction with the Model) and unit tests for MarkVipCommand. + */ +public class MarkVipCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + private Person setVip(Person person, boolean newState) { + PersonBuilder pb = new PersonBuilder(person); + return pb.withVipState(newState).build(); + } + + @Test + public void execute_trueUnfilteredList_success() { + Person personToVip = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + MarkVipCommand markVipCommand = new MarkVipCommand(INDEX_FIRST_PERSON, true); + Person targetPerson = setVip(personToVip, true); + String expectedMessage = String.format(MarkVipCommand.MESSAGE_VIP_PERSON_SUCCESS, Messages.format(personToVip)); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + expectedModel.setPerson(personToVip, targetPerson); + + assertCommandSuccess(markVipCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_falseUnfilteredList_success() { + Person personStartingAsVip = model.getFilteredPersonList().get(INDEX_SECOND_PERSON.getZeroBased()); + Person personToUnvip = setVip(personStartingAsVip, true); + model.setPerson(personStartingAsVip, personToUnvip); + Person targetPerson = setVip(personToUnvip, false); + MarkVipCommand markVipCommand = new MarkVipCommand(INDEX_SECOND_PERSON, false); + + String expectedMessage = String.format(MarkVipCommand.MESSAGE_UNVIP_PERSON_SUCCESS, + Messages.format(personToUnvip)); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + expectedModel.setPerson(personToUnvip, targetPerson); + + assertCommandSuccess(markVipCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_trueUnfilteredList_obsolete() { + Person personStartingAsVip = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person personToVip = setVip(personStartingAsVip, true); + model.setPerson(personStartingAsVip, personToVip); + MarkVipCommand markVipCommand = new MarkVipCommand(INDEX_FIRST_PERSON, true); + String expectedMessage = String.format(MarkVipCommand.MESSAGE_VIP_PERSON_OBSOLETE, + Messages.format(personToVip)); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + + assertCommandSuccess(markVipCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_falseUnfilteredList_obsolete() { + Person personStartingAsNonVip = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + Person personToUnvip = setVip(personStartingAsNonVip, false); + model.setPerson(personStartingAsNonVip, personToUnvip); + MarkVipCommand markVipCommand = new MarkVipCommand(INDEX_FIRST_PERSON, false); + String expectedMessage = String.format(MarkVipCommand.MESSAGE_UNVIP_PERSON_OBSOLETE, + Messages.format(personToUnvip)); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs()); + + assertCommandSuccess(markVipCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidPersonIndexUnfilteredList_failure() { + Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1); + MarkVipCommand markVipCommand = new MarkVipCommand(outOfBoundIndex, false); + + assertCommandFailure(markVipCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + /** + * Update filtered list where index is larger than size of filtered list, + * but smaller than size of address book + */ + @Test + public void execute_invalidPersonIndexFilteredList_failure() { + showPersonAtIndex(model, INDEX_FIRST_PERSON); + Index outOfBoundIndex = INDEX_SECOND_PERSON; + // ensures that outOfBoundIndex is still in bounds of address book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size()); + + MarkVipCommand markVipCommand = new MarkVipCommand(outOfBoundIndex, true); + + assertCommandFailure(markVipCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + @Test + public void equals() { + final MarkVipCommand standardCommand = new MarkVipCommand(INDEX_FIRST_PERSON, true); + + // same values -> returns true + MarkVipCommand commandWithSameValues = new MarkVipCommand(INDEX_FIRST_PERSON, true); + assertTrue(standardCommand.equals(commandWithSameValues)); + + // same object -> returns true + assertTrue(standardCommand.equals(standardCommand)); + + // null -> returns false + assertFalse(standardCommand.equals(null)); + + // different types -> returns false + assertFalse(standardCommand.equals(new ClearCommand())); + + // different index -> returns false + assertFalse(standardCommand.equals(new MarkVipCommand(INDEX_SECOND_PERSON, true))); + + // different target state -> returns false + assertFalse(standardCommand.equals(new MarkVipCommand(INDEX_FIRST_PERSON, false))); + } +} diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java index 6be381d39ba..582cd2a41ef 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/seedu/address/testutil/PersonBuilder.java @@ -26,6 +26,7 @@ public class PersonBuilder { private Email email; private Address address; private Set tags; + private boolean isVip; /** * Creates a {@code PersonBuilder} with the default details. @@ -36,6 +37,7 @@ public PersonBuilder() { email = new Email(DEFAULT_EMAIL); address = new Address(DEFAULT_ADDRESS); tags = new HashSet<>(); + isVip = false; } /** @@ -47,6 +49,7 @@ public PersonBuilder(Person personToCopy) { email = personToCopy.getEmail(); address = personToCopy.getAddress(); tags = new HashSet<>(personToCopy.getTags()); + isVip = personToCopy.isVip(); } /** @@ -89,8 +92,16 @@ public PersonBuilder withEmail(String email) { return this; } + /** + * Sets the {@code isVip} of the {@code Person} that we are building. + */ + public PersonBuilder withVipState(boolean isVip) { + this.isVip = isVip; + return this; + } + public Person build() { - return new Person(name, phone, email, address, tags); + return new Person(name, phone, email, address, tags, isVip); } } From 0479e437844d9e2f1b85b4779c502d6c2aff395f Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Wed, 16 Oct 2024 18:06:26 +0800 Subject: [PATCH 13/17] Remove obsolete /v prefix /v is not used in the implementation of MarkVip. Let's remove it. Also, let's make MarkVipCommandParser implement the Parser interface. --- docs/UserGuide.md | 8 +++--- .../logic/commands/MarkVipCommand.java | 3 +- .../seedu/address/logic/parser/CliSyntax.java | 1 - .../logic/parser/MarkVipCommandParser.java | 2 +- .../parser/MarkVipCommandParserTest.java | 28 +++++++++++++++++++ 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 7cc9481e22b..409f61cc21b 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -176,7 +176,7 @@ Furthermore, certain edits can cause the AddressBook to behave in unexpected way Marks the specified person from the address book as a VIP or removes said label. -Format: `vip INDEX v/IS_VIP` +Format: `vip INDEX IS_VIP` * Affects the person at the specified `INDEX`. * The index refers to the index number shown in the displayed person list. @@ -184,8 +184,8 @@ Format: `vip INDEX v/IS_VIP` * IS_VIP should either be `true` or `false`, corresponding to whether you intend to mark the target as a VIP or remove such a mark. Examples: -* `list` followed by `vip 2 v/true` marks the 2nd person in the address book as a VIP. -* `find Betsy` followed by `vip 1 v/false` removes VIP status from the 1st person in the results of the `find` command. +* `list` followed by `vip 2 true` marks the 2nd person in the address book as a VIP. +* `find Betsy` followed by `vip 1 false` removes VIP status from the 1st person in the results of the `find` command. ### Archiving data files `[coming in v2.0]` @@ -217,5 +217,5 @@ Action | Format, Examples **Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`
e.g.,`edit 2 n/James Lee e/jameslee@example.com` **Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` **List** | `list` -**Vip** | `vip INDEX v/IS_VIP`
e.g., `vip 3 v/true` +**Vip** | `vip INDEX IS_VIP`
e.g., `vip 3 true` **Help** | `help` diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 1f3b6ead5b5..20edfa5f321 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -1,6 +1,5 @@ package seedu.address.logic.commands; -import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; import java.util.List; @@ -27,7 +26,7 @@ public class MarkVipCommand extends Command { public static final String MESSAGE_USAGE = COMMAND_WORD + ": Marks or unmarks the person identified by the index " + "number used in the displayed person list as a VIP.\n" - + "Parameters: INDEX (must be a positive integer) v/IS_VIP (must be \"true\" or \"false\")\n" + + "Parameters: INDEX (must be a positive integer) IS_VIP (must be \"true\" or \"false\")\n" + "Example: " + COMMAND_WORD + " 1 true"; public static final String MESSAGE_VIP_PERSON_SUCCESS = "Person marked as a VIP: %1$s"; diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 6c4284b2314..919ee4ad194 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -11,6 +11,5 @@ public class CliSyntax { public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); - public static final Prefix PREFIX_MARKVIP = new Prefix("v/"); public static final Prefix PREFIX_COMMENT = new Prefix("c/"); } diff --git a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java index 57817f4c996..982e6cb1919 100644 --- a/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java @@ -10,7 +10,7 @@ /** * Parses input arguments and creates a new MarkVipCommand. */ -public class MarkVipCommandParser { +public class MarkVipCommandParser implements Parser { /** * Parses the given {@code String} of arguments in the context of the MarkVipCommand diff --git a/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java b/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java new file mode 100644 index 00000000000..9ce3d58299a --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java @@ -0,0 +1,28 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.MarkVipCommand; + +public class MarkVipCommandParserTest { + + private static final String MESSAGE_INVALID_FORMAT = + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE); + + private MarkVipCommandParser parser = new MarkVipCommandParser(); + + @Test + public void parse_missingParts_failure() { + // no index specified + assertParseFailure(parser, CliSyntax.PREFIX_MARKVIP + "true", MESSAGE_INVALID_FORMAT); + + // new state not specified + assertParseFailure(parser, "1", MESSAGE_INVALID_FORMAT); + + // no index and no new state specified + assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT); + } +} From 86f34262e57e319a36e052c204876a7efba54bae Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Wed, 16 Oct 2024 18:21:20 +0800 Subject: [PATCH 14/17] Add tests for MarkVipCommandParser --- .../parser/MarkVipCommandParserTest.java | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java b/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java index 9ce3d58299a..2bb322b236b 100644 --- a/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/MarkVipCommandParserTest.java @@ -2,9 +2,11 @@ import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; import org.junit.jupiter.api.Test; +import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.MarkVipCommand; public class MarkVipCommandParserTest { @@ -17,7 +19,7 @@ public class MarkVipCommandParserTest { @Test public void parse_missingParts_failure() { // no index specified - assertParseFailure(parser, CliSyntax.PREFIX_MARKVIP + "true", MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, "true", MESSAGE_INVALID_FORMAT); // new state not specified assertParseFailure(parser, "1", MESSAGE_INVALID_FORMAT); @@ -25,4 +27,31 @@ public void parse_missingParts_failure() { // no index and no new state specified assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT); } + + @Test + public void parse_invalidArgs_failure() { + // negative index + assertParseFailure(parser, "-5 false", MESSAGE_INVALID_FORMAT); + + // zero index + assertParseFailure(parser, "0 true", MESSAGE_INVALID_FORMAT); + + // invalid arguments being parsed as preamble + assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT); + + // prefix detected in args + assertParseFailure(parser, "1 i/false", MESSAGE_INVALID_FORMAT); + + // too many indices + assertParseFailure(parser, "2 4 true", MESSAGE_INVALID_FORMAT); + + // too many booleans + assertParseFailure(parser, "2 false true", MESSAGE_INVALID_FORMAT); + } + + @Test + public void parse_success() { + assertParseSuccess(parser, "3 true", new MarkVipCommand(Index.fromOneBased(3), true)); + assertParseSuccess(parser, "1 false", new MarkVipCommand(Index.fromOneBased(1), false)); + } } From a18a7cf8300a9f4877e17e9e87b7ec45e37e9c6c Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Wed, 16 Oct 2024 18:40:04 +0800 Subject: [PATCH 15/17] Update tests for edited classes --- .../address/logic/parser/AddressBookParserTest.java | 9 +++++++++ src/test/java/seedu/address/model/person/PersonTest.java | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index b41aa71ff17..8a2cda60c43 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -6,6 +6,7 @@ import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; import java.util.Arrays; import java.util.List; @@ -21,6 +22,7 @@ import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.MarkVipCommand; import seedu.address.logic.commands.SearchCommand; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.person.NameContainsKeywordsPredicate; @@ -88,6 +90,13 @@ public void parseCommand_list() throws Exception { assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand); } + @Test + public void parseCommand_markVip() throws Exception { + MarkVipCommand command = (MarkVipCommand) parser.parseCommand(MarkVipCommand.COMMAND_WORD + " " + + INDEX_SECOND_PERSON.getOneBased() + " true"); + assertEquals(command, new MarkVipCommand(INDEX_SECOND_PERSON, true)); + } + @Test public void parseCommand_unrecognisedInput_throwsParseException() { assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), () diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java index 1c6709c5e12..c39a10043a7 100644 --- a/src/test/java/seedu/address/model/person/PersonTest.java +++ b/src/test/java/seedu/address/model/person/PersonTest.java @@ -88,6 +88,10 @@ public void equals() { // different tags -> returns false editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build(); assertFalse(ALICE.equals(editedAlice)); + + // different VIP state -> returns false + editedAlice = new PersonBuilder(ALICE).withVipState(true).build(); + assertFalse(ALICE.equals(editedAlice)); } @Test From a99d6647f04ce7921c501d3462efe6c28c1499a9 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Thu, 17 Oct 2024 17:47:36 +0800 Subject: [PATCH 16/17] Resolve merge conflicts --- .../java/seedu/address/logic/commands/MarkVipCommand.java | 4 +++- src/main/java/seedu/address/model/person/Person.java | 4 ++++ .../java/seedu/address/storage/JsonAdaptedPerson.java | 8 +++++--- src/test/java/seedu/address/testutil/PersonBuilder.java | 3 +++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java index 20edfa5f321..a9d971ea9d6 100644 --- a/src/main/java/seedu/address/logic/commands/MarkVipCommand.java +++ b/src/main/java/seedu/address/logic/commands/MarkVipCommand.java @@ -10,6 +10,7 @@ import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; import seedu.address.model.person.Address; +import seedu.address.model.person.Comment; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Person; @@ -73,8 +74,9 @@ public CommandResult execute(Model model) throws CommandException { Address address = personToMark.getAddress(); Email email = personToMark.getEmail(); Phone phone = personToMark.getPhone(); + Comment comment = personToMark.getComment(); Set tags = personToMark.getTags(); - Person updatedPerson = new Person(name, phone, email, address, tags, newState); + Person updatedPerson = new Person(name, phone, email, address, comment, tags, newState); model.setPerson(personToMark, updatedPerson); return new CommandResult(String.format(messageSuccess, Messages.format(personToMark))); } diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 2a55fbd45dc..133ae0df66f 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -27,6 +27,10 @@ public class Person { private final boolean isVip; private final Comment comment; + public Person(Name name, Phone phone, Email email, Address address, Comment comment, Set tags) { + this(name, phone, email, address, comment, tags, false); + } + /** * Every field must be present and not null. */ diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index ff4be668c7a..107de59f27b 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -39,7 +39,8 @@ class JsonAdaptedPerson { @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("comment") String comment, @JsonProperty("tags") List tags, @JsonProperty("isVip") boolean isVip) { + @JsonProperty("comment") String comment, @JsonProperty("tags") List tags, + @JsonProperty("isVip") boolean isVip) { this.name = name; this.phone = phone; this.email = email; @@ -54,8 +55,9 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone /** * Constructs a {@code JsonAdaptedPerson} with the given person details, treating isVip as false. */ - public JsonAdaptedPerson(String name, String phone, String email, String address, List tags) { - this(name, phone, email, address, tags, false); + public JsonAdaptedPerson(String name, String phone, String email, String address, + String comment, List tags) { + this(name, phone, email, address, comment, tags, false); } /** diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java index 1f8dcc83cdf..8adb0923b68 100644 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ b/src/test/java/seedu/address/testutil/PersonBuilder.java @@ -102,6 +102,9 @@ public PersonBuilder withEmail(String email) { */ public PersonBuilder withVipState(boolean isVip) { this.isVip = isVip; + return this; + } + /** * Sets the {@code Comment} of the {@code Person} that we are building. */ From 680df863a378807831277ed2176c8006bb3df959 Mon Sep 17 00:00:00 2001 From: 1st2GetThisName Date: Thu, 17 Oct 2024 18:50:40 +0800 Subject: [PATCH 17/17] Add missing Javadoc comment --- src/main/java/seedu/address/model/person/Person.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index 133ae0df66f..ae33931da85 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -27,6 +27,9 @@ public class Person { private final boolean isVip; private final Comment comment; + /** + * Every field must be present and not null. The customer will start as a non-VIP. + */ public Person(Name name, Phone phone, Email email, Address address, Comment comment, Set tags) { this(name, phone, email, address, comment, tags, false); }