Skip to content

Commit

Permalink
Merge pull request #63 from zekone/add-tag
Browse files Browse the repository at this point in the history
Add tag-related features
  • Loading branch information
AndrewJanong authored Nov 1, 2023
2 parents 3ba728f + 36e01b7 commit 2910839
Show file tree
Hide file tree
Showing 19 changed files with 760 additions and 30 deletions.
29 changes: 16 additions & 13 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -543,17 +543,22 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli

**Extensions**

* 1a. User inputs a non-alphanumeric tag.
* 1a. User inputs incomplete data.

* 1a1. KeepInTouch shows a message indicating that tags should be alphanumeric.
* 1a1. KeepInTouch shows a message indicating incomplete data.

Use case resumes at step 1.
Use case ends.

* 1b. User inputs a contact that does not exist.
* 1b. User inputs a non-alphanumeric tag.
* 1b1. KeepInTouch shows a message indicating that tags should be alphanumeric.

Use case ends.

* 1b1. KeepInTouch shows a message indicating the contact cannot be found.
* 1c. User inputs a contact that does not exist.

Use case resumes at step 1.
* 1c1. KeepInTouch shows a message indicating that the contact cannot be found.

Use case ends.

**Use case: UC12 - Delete tags from a contact**

Expand All @@ -572,15 +577,14 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli

Use case ends.

* 1b. User inputs a contact that does not exist.

* 1b1. KeepInTouch shows a message indicating that the contact cannot be found.
* 1b. User inputs a non-alphanumeric tag.
* 1b1. KeepInTouch shows a message indicating that tags should be alphanumeric.

Use case ends.

* 1c. User inputs a tag that does not exist.
* 1c. User inputs a contact that does not exist.

* 1c1. KeepInTouch shows a message indicating that the tags cannot be found.
* 1c1. KeepInTouch shows a message indicating that the contact cannot be found.

Use case ends.

Expand All @@ -600,7 +604,6 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 1a1. KeepInTouch shows a message indicating incomplete data.

Use case ends.

* 1b. User inputs a contact that does not exist.

* 1b1. KeepInTouch shows a message indicating that the contact cannot be found.
Expand All @@ -609,7 +612,7 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli

* 1c. User inputs a tag that does not exist.

* 1c1. KeepInTouch shows a message indicating that the tags cannot be found.
* 1c1. KeepInTouch shows a message indicating that the tag cannot be found.

Use case ends.

Expand Down
40 changes: 40 additions & 0 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ If you can type fast, KeepInTouch can get your contact management tasks done fas
* [Adding a person: `add contact`](#adding-a-person--add-contact)
* [Listing all persons: `list contact`](#listing-all-persons--list-contact)
* [Deleting a person: `delete contact`](#deleting-a-person--delete-contact)
* [Adding tags: `add tag`](#adding-tags--add-tag)
* [Deleting tags: `delete tag`](#deleting-tags--delete-tag)
* [Adding a note: `add note`](#adding-notes-to-a-contact--add-note)
* [Listing all notes: `list notes`](#listing-all-notes--list-notes)
* [Deleting a note: `delete note`](#deleting-a-note--delete-note)
Expand Down Expand Up @@ -71,6 +73,9 @@ If you can type fast, KeepInTouch can get your contact management tasks done fas

* `CONTACT_ID` is the number that is on the left of the person's name in each person card.

* Items with ``​ after them can be used multiple times.<br>
e.g. `[-t TAGNAME]…​` can be used as `-t frontend`, `-t frontend -t java` etc.

* Parameters can be in any order.<br>
e.g. if the command specifies `-n NAME -t NOTE_TITLE`, `-t NOTE_TITLE -n NAME` is also acceptable.

Expand Down Expand Up @@ -117,6 +122,39 @@ Format: `delete contact NAME`
Examples:
* `list contact` followed by `delete contact Aaron` deletes the contact with the name Aaron.

### Adding tags : `add tag`

Adds one or more tags to a contact.

Format: `add tag -id CONTACT_ID -t TAGNAME...`

* Adds one or more tags to a contact.
* Duplicates are accepted but only unique tags will be added.

Requirements:
* `TAGNAME` must be alphanumeric, with no spaces.

Examples:
* `add tag -id 1 -t frontend` adds a tag with tag name "frontend" to the first contact in the contact list.
* `add tag -id 1 -t frontend -t java` adds two tags with tag name "frontend" and "java" to the first contact in the contact list.


### Deleting tags : `delete tag`

Deletes one or more tags to a contact.

Format: `delete tag -id CONTACT_ID -t TAGNAME...`

* Deletes one or more tags to a contact, regardless if the tag exists in the contact or not.
* Duplicates are accepted but only unique tags will be added.

Requirements:
* `TAGNAME` must be alphanumeric, with no spaces.

Examples:
* `delete tag -id 1 -t frontend` deletes a tag with tag name "frontend" from the first contact in the contact list.
* `add tag -id 1 -t frontend -t java` deletes two tags with tag name "frontend" and "java" from the first contact in the contact list.

### Adding notes to a contact: `add note`

Adds a note to a contact from the contact list.
Expand Down Expand Up @@ -232,6 +270,8 @@ Action | Format, Examples
**Add Contact** | `add contact -n NAME -p PHONE_NUMBER -a ADDRESS -e EMAIL` <br> e.g., `add contact -n Aaron -p 12345678 -a Baker Street 12 -e [email protected]`
**Delete Contact** | `delete contact NAME`<br> e.g., `delete contact Aaron`
**List Contact** | `list contact`
**Add Tag** | `add tag -id CONTACT_ID -t TAGNAME` <br> eg., `add tag -id 1 -t frontend`
**Delete Tag** | `delete tag -id CONTACT_ID -t TAGNAME` <br> eg., `delete tag -id 1 -t frontend`
**Add Note** | `add note -n NAME -t NOTE_TITLE -c NOTE_CONTENT` <br> e.g., `add note -n Daniel -t Open Position -e Applications for SWE full-time positions will open soon`
**Delete Note** | `delete note -n NAME -t NOTE_TITLE`<br> e.g., `delete note -n Aaron -t Meeting Topics`
**List Notes** | `list notes`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
Expand All @@ -26,12 +27,14 @@ public class AddPersonCommand extends AddCommand {
+ PREFIX_NAME + " NAME "
+ PREFIX_PHONE + " PHONE "
+ PREFIX_EMAIL + " EMAIL "
+ PREFIX_ADDRESS + " ADDRESS" + "\n"
+ PREFIX_ADDRESS + " ADDRESS "
+ PREFIX_TAG + " TAGNAME" + "\n"
+ "Example: " + COMMAND_WORD + " " + SECONDARY_COMMAND_WORD
+ PREFIX_NAME + " John Doe "
+ PREFIX_PHONE + " 98765432 "
+ PREFIX_EMAIL + " [email protected] "
+ PREFIX_ADDRESS + " 311, Clementi Ave 2, #02-25 ";
+ PREFIX_ADDRESS + " 311, Clementi Ave 2, #02-25 "
+ PREFIX_TAG + " frontend ";

public static final String MESSAGE_SUCCESS = "New contact added: %1$s";
public static final String MESSAGE_DUPLICATE_PERSON = "This contact already exists in the contact list";
Expand Down
79 changes: 79 additions & 0 deletions src/main/java/seedu/address/logic/commands/AddTagCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.Set;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.ContactID;
import seedu.address.model.person.Person;
import seedu.address.model.tag.Tag;

/**
* The command handler for {@code add tag} command
*/
public class AddTagCommand extends AddCommand {
public static final String SECONDARY_COMMAND_WORD = "tag";
public static final String MESSAGE_SUCCESS = "New tags added: ";

public static final String MESSAGE_USAGE = COMMAND_WORD + " " + SECONDARY_COMMAND_WORD
+ ": Adds tags to a contact from the contact list.\n"
+ "Usage: add tag -id CONTACT_ID -t TAGNAME";
public static final String MESSAGE_PERSON_NOT_FOUND = "Can not find the target contact with ID: ";

private final Set<Tag> toAdd;
private final int contactId;

/**
* Creates an AddTagCommand to add the specified {@code Tag}(s).
*/
public AddTagCommand(int contactId, Set<Tag> tagList) {
requireNonNull(tagList);
this.contactId = contactId;
this.toAdd = tagList;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
Person person = model.findPersonByUserFriendlyId(ContactID.fromInt(this.contactId));
if (person == null) {
throw new CommandException(MESSAGE_PERSON_NOT_FOUND + this.contactId);
}
person.addTags(this.toAdd);

final StringBuilder builder = new StringBuilder();
builder.append(MESSAGE_SUCCESS);
toAdd.forEach(builder::append);

return new CommandResult(builder.toString());
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

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

AddTagCommand otherAddNoteCommand = (AddTagCommand) other;

boolean equalToAdd = toAdd.equals(otherAddNoteCommand.toAdd);
boolean equalContactId = (contactId == otherAddNoteCommand.contactId);
return equalToAdd && equalContactId;
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("toAdd", toAdd)
.add("contactId", contactId)
.toString();
}
}
78 changes: 78 additions & 0 deletions src/main/java/seedu/address/logic/commands/DeleteTagCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.Set;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.ContactID;
import seedu.address.model.person.Person;
import seedu.address.model.tag.Tag;

/**
* The command handler for {@code delete tag} command
*/
public class DeleteTagCommand extends DeleteCommand {
public static final String SECONDARY_COMMAND_WORD = "tag";
public static final String MESSAGE_USAGE = COMMAND_WORD + " "
+ SECONDARY_COMMAND_WORD + ": Delete one or more tags from a contact.\n"
+ "Usage: delete tag -id CONTACT_ID -t TAGNAME";
public static final String MESSAGE_PERSON_NOT_FOUND = "Can not find the target contact with ID: ";
public static final String MESSAGE_SUCCESS = "Successfully deleted tags: ";

private final Set<Tag> toDelete;
private final int contactId;

/**
* Creates an DeleteTagCommand to delete the specified {@code Tag}(s).
*/
public DeleteTagCommand(int contactId, Set<Tag> tagList) {
requireNonNull(tagList);
this.contactId = contactId;
this.toDelete = tagList;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
Person person = model.findPersonByUserFriendlyId(ContactID.fromInt(this.contactId));
if (person == null) {
throw new CommandException(MESSAGE_PERSON_NOT_FOUND + this.contactId);
}
person.removeTags(toDelete);

final StringBuilder builder = new StringBuilder();
builder.append(MESSAGE_SUCCESS);
toDelete.forEach(builder::append);

return new CommandResult(builder.toString());
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

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

DeleteTagCommand otherAddNoteCommand = (DeleteTagCommand) other;

boolean equalToDelete = toDelete.equals(otherAddNoteCommand.toDelete);
boolean equalContactId = (contactId == otherAddNoteCommand.contactId);
return equalToDelete && equalContactId;
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("toDelete", toDelete)
.add("contactId", contactId)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import seedu.address.logic.commands.AddEventCommand;
import seedu.address.logic.commands.AddNoteCommand;
import seedu.address.logic.commands.AddPersonCommand;
import seedu.address.logic.commands.AddTagCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand All @@ -24,6 +25,8 @@ public AddCommand parse(String userInput) throws ParseException {
return new AddEventCommandParser().parse(args);
case AddNoteCommand.SECONDARY_COMMAND_WORD:
return new AddNoteCommandParser().parse(args);
case AddTagCommand.SECONDARY_COMMAND_WORD:
return new AddTagCommandParser().parse(args);
default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/seedu/address/logic/parser/AddTagCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.Messages.MESSAGE_INVALID_INTEGER_ARGUMENT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PERSON_ID;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import java.util.Set;

import seedu.address.logic.commands.AddTagCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.tag.Tag;

/**
* Parses input arguments and creates a new AddTagCommand object
*/
public class AddTagCommandParser implements Parser<AddTagCommand> {
@Override
public AddTagCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_PERSON_ID,
PREFIX_TAG);

if (!ParserUtil.arePrefixesPresent(argMultimap, PREFIX_PERSON_ID, PREFIX_TAG)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTagCommand.MESSAGE_USAGE));
}

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_PERSON_ID);

Set<Tag> tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));

int contactId = -1;
try {
contactId = Integer.parseInt(argMultimap.getValue(PREFIX_PERSON_ID).get());
} catch (NumberFormatException e) {
throw new ParseException(String.format(MESSAGE_INVALID_INTEGER_ARGUMENT, e.getMessage()));
}

return new AddTagCommand(contactId, tagList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import seedu.address.logic.commands.DeleteEventCommand;
import seedu.address.logic.commands.DeleteNoteCommand;
import seedu.address.logic.commands.DeletePersonCommand;
import seedu.address.logic.commands.DeleteTagCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand All @@ -23,6 +24,8 @@ public DeleteCommand parse(String userInput) throws ParseException {
return new DeleteNoteCommandParser().parse(args);
case DeleteEventCommand.SECONDARY_COMMAND_WORD:
return new DeleteEventCommandParser().parse(args);
case DeleteTagCommand.SECONDARY_COMMAND_WORD:
return new DeleteTagCommandParser().parse(args);
default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
Loading

0 comments on commit 2910839

Please sign in to comment.