Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
timothysashimi authored Mar 21, 2024
2 parents 41a405e + 0839077 commit 9bffa8f
Show file tree
Hide file tree
Showing 29 changed files with 910 additions and 217 deletions.
9 changes: 9 additions & 0 deletions docs/diagrams/ModelClassDiagram.puml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ Name -[hidden]right-> Phone
Phone -[hidden]right-> Address
Address -[hidden]right-> Email

Person "1" -- "0..*" Meeting

' AddMeetingCommand Class and its relation to Meeting
Class AddMeetingCommand {
+execute(): CommandResult
}
AddMeetingCommand ..> Meeting : creates

ModelManager --> "~* filtered" Person
ModelManager --> "~* filtered" Meeting
@enduml
```
4 changes: 4 additions & 0 deletions docs/team/zixuan.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ The user interacts with it using a CLI, and it has a GUI created with JavaFX. It
Given below are my contributions to the project.

* **New Feature**:
* Added the addMeeting command
* Edited Meeting Model class
* **Code contributed**:
* [RepoSense link](https://nus-cs2103-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=chewbum&tabRepo=AY2324S2-CS2103-F08-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)


* **Project management**:
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/seedu/address/logic/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import seedu.address.model.meeting.Meeting;
import seedu.address.model.person.Person;


/**
* Container for user visible messages.
*/
Expand Down Expand Up @@ -49,6 +50,19 @@ public static String format(Person person) {
person.getTags().forEach(builder::append);
return builder.toString();
}
/**
* Formats the {@code meeting} for display to the user.
*/
public static String format(Meeting meeting) {
final StringBuilder builder = new StringBuilder();
builder.append("Client: ")
.append(meeting.getClientName())
.append("DateTime: ")
.append(meeting.getDateTime())
.append("; Description: ")
.append(meeting.getDescription());
return builder.toString();
}

/**
* Formats the {@code meeting} for display to the user.
Expand Down
122 changes: 122 additions & 0 deletions src/main/java/seedu/address/logic/commands/AddMeetingCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;

import java.time.LocalDateTime;
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.meeting.Meeting;
import seedu.address.model.person.Person;

/**
* Represents a command to add a meeting associated with a specific client in the address book.
* This command adds a new meeting to the address book, ensuring that no duplicate meetings are added.
* A meeting is considered a duplicate if it has the same client, date, and description as an existing meeting.
*/
public class AddMeetingCommand extends Command {
public static final String COMMAND_WORD = "addMeeting";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a meeting to the "
+ "client identified by the index number. \n"
+ "Parameters: client/ CLIENT_INDEX dt/ DATE_TIME /d DESCRIPTION \n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_CLIENT_INDEX + "1 "
+ PREFIX_DATETIME + "02-01-2024 12:00 "
+ PREFIX_DESCRIPTION + "sign life plan";


public static final String MESSAGE_SUCCESS = "New meeting added: %1$s";
public static final String MESSAGE_DUPLICATE_MEETING = "This meeting already exists in the address book";

private final Index clientIndex;
private final LocalDateTime dateTime;
private final String description;

/**
* Creates an {@code AddMeetingCommand} to add the specified {@code Meeting}.
*
* @param dateTime The date and time of the meeting.
* @param description A description of the meeting.
* @param clientIndex The index of the client in the filtered person list to whom the meeting is to be added.
* @throws NullPointerException if any of the input parameters are null.
*/

public AddMeetingCommand(LocalDateTime dateTime, String description, Index clientIndex) {
if (dateTime == null || description == null || clientIndex == null) {
throw new NullPointerException();
}
this.dateTime = dateTime;
this.description = description;
this.clientIndex = clientIndex;
}

/**
* Executes the AddMeeting command to add a new meeting associated with a client in the address book.
* <p>
* The method retrieves the client based on the index provided, creates a new meeting with the specified date, time,
* and description, and then adds this meeting to the model if it does not already exist to ensure uniqueness.
* <p>
* If the specified client index is invalid or the meeting already exists, it throws a CommandException.
*
* @param model The model in which the meeting will be added.
* @return A CommandResult object containing the success message.
* @throws CommandException If the client index is invalid or the meeting already exists in the model.
*/
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Person> lastShownList = model.getFilteredPersonList();

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

Person client = lastShownList.get(clientIndex.getZeroBased());
Meeting meetingToAdd = new Meeting(description, dateTime, client);

if (model.hasMeeting(meetingToAdd) && client.hasExistingMeeting(meetingToAdd)) {
throw new CommandException(MESSAGE_DUPLICATE_MEETING);
}
model.addMeeting(meetingToAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(meetingToAdd)));
}

/**
* Checks if another object is equal to this AddMeetingCommand instance.
* <p>
* The equality check is based on whether the other object is an instance of AddMeetingCommand
* and whether the meetings to be added are the same in terms of client, date, time, and description.
* This ensures that two AddMeetingCommand objects are considered equal if they are attempting
* to add the same meeting.
* <p>
* This method is crucial for command comparisons, especially when testing or when the application
* logic requires comparing different commands.
*
* @param other The object to compare this AddMeetingCommand against.
* @return true if the given object represents an AddMeetingCommand equivalent to this instance, false otherwise.
*/

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

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

AddMeetingCommand otherCommand = (AddMeetingCommand) other;
return dateTime.equals(otherCommand.dateTime)
&& description.equals(otherCommand.description)
&& clientIndex.equals(otherCommand.clientIndex);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
public class DeleteMeetingCommand extends Command {

public static final String COMMAND_WORD = "delete meeting";
public static final String COMMAND_WORD = "deleteMeeting";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Deletes the meeting of a particular client identified by the "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_INDEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATETIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;

import java.time.LocalDateTime;
import java.util.stream.Stream;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.AddMeetingCommand;
import seedu.address.logic.parser.exceptions.ParseException;

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

/**
* Parses the given {@code String} of arguments in the context of the AddMeetingCommand
* and returns an AddMeetingCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public AddMeetingCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION);
System.out.println(!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION));
System.out.println(!argMultimap.getPreamble().isEmpty());
if (!arePrefixesPresent(argMultimap, PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddMeetingCommand.MESSAGE_USAGE));
}

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_CLIENT_INDEX, PREFIX_DATETIME, PREFIX_DESCRIPTION);
Index clientIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_CLIENT_INDEX).get());
LocalDateTime dateTime = ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATETIME).get());
String description = ParserUtil.parseDescription(argMultimap.getValue(PREFIX_DESCRIPTION).get());


return new AddMeetingCommand(dateTime, description, clientIndex);
}

/**
* Returns true if none of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
*/
private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}

}
93 changes: 37 additions & 56 deletions src/main/java/seedu/address/logic/parser/AddressBookParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.commands.AddMeetingCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.DeleteCommand;
Expand All @@ -19,7 +20,6 @@
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.ViewCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand All @@ -31,8 +31,6 @@ public class AddressBookParser {
* Used for initial separation of command word and args.
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?<commandWord>\\S+)(?<arguments>.*)");
private static final Pattern MEETING_COMMAND_TWO_ARGS_FORMAT = Pattern
.compile("(?<commandWord>\\S+\\s+\\S+)(?:\\s+(?<firstArgument>\\d+))(?:\\s+(?<secondArgument>\\d+))");
private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);

/**
Expand All @@ -43,73 +41,56 @@ public class AddressBookParser {
* @throws ParseException if the user input does not conform the expected format
*/
public Command parseCommand(String userInput) throws ParseException {
final Matcher basicCommandMatcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
final Matcher meetingCommandTwoArgsMatcher = MEETING_COMMAND_TWO_ARGS_FORMAT.matcher(userInput.trim());

if (basicCommandMatcher.matches()) {
final String commandWord = basicCommandMatcher.group("commandWord");
final String arguments = basicCommandMatcher.group("arguments");

// Note to developers: Change the log level in config.json to enable lower level
// (i.e., FINE, FINER and lower)
// log messages such as the one below.
// Lower level log messages are used sparingly to minimize noise in the code.
logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);

switch (commandWord) {
final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}

case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);
final String commandWord = matcher.group("commandWord");
final String arguments = matcher.group("arguments");

case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
// Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
// log messages such as the one below.
// Lower level log messages are used sparingly to minimize noise in the code.
logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);

case DeleteCommand.COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);
switch (commandWord) {

case ClearCommand.COMMAND_WORD:
return new ClearCommand();
case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);

case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);

case ListCommand.COMMAND_WORD:
return new ListCommand();
case DeleteCommand.COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);

case ExitCommand.COMMAND_WORD:
return new ExitCommand();
case ClearCommand.COMMAND_WORD:
return new ClearCommand();

case HelpCommand.COMMAND_WORD:
return new HelpCommand();
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);

case ViewCommand.COMMAND_WORD:
return new ViewCommandParser().parse(arguments);
case ListCommand.COMMAND_WORD:
return new ListCommand();

case EditMeetingCommand.COMMAND_WORD:
return new EditMeetingCommandParser().parse(arguments);
case EditMeetingCommand.COMMAND_WORD:
return new EditMeetingCommandParser().parse(arguments);

default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
} else if (meetingCommandTwoArgsMatcher.matches()) {
final String commandWord = basicCommandMatcher.group("commandWord");
final String firstArgument = basicCommandMatcher.group("firstArgument");
final String secondArgument = basicCommandMatcher.group("secondArgument");
case ExitCommand.COMMAND_WORD:
return new ExitCommand();

switch (commandWord) {
case DeleteMeetingCommand.COMMAND_WORD:
return new DeleteMeetingCommandParser().parse(firstArgument, secondArgument);
case HelpCommand.COMMAND_WORD:
return new HelpCommand();

default:
logger.finer("This user input caused a ParseException: " + userInput);
System.out.println("Unknown");
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
} else {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
case AddMeetingCommand.COMMAND_WORD:
return new AddMeetingCommandParser().parse(arguments);
case DeleteMeetingCommand.COMMAND_WORD:
return new DeleteMeetingCommandParser().parse(arguments);
default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}

}

}
5 changes: 3 additions & 2 deletions src/main/java/seedu/address/logic/parser/CliSyntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ public class CliSyntax {
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
public static final Prefix PREFIX_TAG = new Prefix("t/");

public static final Prefix PREFIX_DATETIME = new Prefix("d/");

public static final Prefix PREFIX_CLIENT = new Prefix("c/");

public static final Prefix PREFIX_CLIENT_INDEX = new Prefix("clientIndex/");

public static final Prefix PREFIX_MEETING_INDEX = new Prefix("meetingIndex/");

public static final Prefix PREFIX_DATETIME = new Prefix("dt/");
public static final Prefix PREFIX_DESCRIPTION = new Prefix("d/");

}
Loading

0 comments on commit 9bffa8f

Please sign in to comment.