Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Schedule Feature (Partial) #142

Merged
merged 8 commits into from
Mar 28, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/seedu/address/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import seedu.address.model.ReadOnlyAppointmentBook;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
import seedu.address.model.schedule.ReadOnlyScheduleTracker;
import seedu.address.model.schedule.ScheduleTracker;
import seedu.address.model.util.SampleDataUtil;
import seedu.address.storage.AddressBookStorage;
import seedu.address.storage.AppointmentBookStorage;
Expand Down Expand Up @@ -89,6 +91,7 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
Optional<ReadOnlyAppointmentBook> appointmentBookOptional;
ReadOnlyAddressBook initialData;
ReadOnlyAppointmentBook initialAppointments;
ReadOnlyScheduleTracker initialSchedules;

try {
addressBookOptional = storage.readAddressBook();
Expand Down Expand Up @@ -117,6 +120,7 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
initialAppointments = new AppointmentBook();
}

initialSchedules = new ScheduleTracker();
return new ModelManager(initialData, userPrefs, initialAppointments);
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/address/commons/core/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
public static final String MESSAGE_INVALID_SCHEDULE_DISPLAYED_INDEX = "The schedule index provided is invalid";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_INVALID_APPOINTMENT_DISPLAYED_INDEX =
"The appointment index provided is invalid";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package seedu.address.logic.commands.schedulecommands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME_FROM;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME_TO;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TITLE;

import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.schedule.Schedule;

/**
* Adds a schedule to the schedule list.
*/
public class AddScheduleCommand extends Command {

public static final String COMMAND_WORD = "add_schedule";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a schedule to the schedule list. "
+ "Parameters: "
+ PREFIX_TITLE + "TITLE "
+ PREFIX_DATE + "DATE "
+ PREFIX_TIME_FROM + "TIME FROM "
+ PREFIX_TIME_TO + "TIME TO "
+ PREFIX_DESCRIPTION + "DESCRIPTION\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_TITLE + "Math Tuition Homework "
+ PREFIX_DATE + "2021-3-1 "
+ PREFIX_TIME_FROM + "08:00am "
+ PREFIX_TIME_TO + "10:00am "
+ PREFIX_DESCRIPTION + "Page 10 to 13";

public static final String MESSAGE_SUCCESS = "New schedule added: %1$s";
public static final String MESSAGE_DUPLICATE_SCHEDULE = "This schedule already exists in the list";

private final Schedule toAdd;

/**
* Primary constructor to accept a schedule and add it to schedule list.
*
* @param schedule Schedule to add
*/
public AddScheduleCommand(Schedule schedule) {
requireNonNull(schedule);
toAdd = schedule;
}

/**
* Main execute method that creates adds a new schedule to the schedule list
*
* @param model {@code Model} which the command should operate on.
* @return CommandResult indicating success or failure of add operation
* @throws CommandException if {@code Schedule} already exists
*/
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);

if (model.hasSchedule(toAdd)) {
throw new CommandException(MESSAGE_DUPLICATE_SCHEDULE);
} else {
model.addSchedule(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package seedu.address.logic.commands.schedulecommands;

import static java.util.Objects.requireNonNull;

import java.util.List;

import seedu.address.commons.core.Messages;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.schedule.Schedule;

/**
* Deletes an schedule identified using it's displayed index from the schedule list.
*/
public class DeleteScheduleCommand extends Command {

public static final String COMMAND_WORD = "delete_schedule";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Deletes the schedule identified by the index number used in the displayed schedule list.\n"
+ "Parameters: INDEX (must be a positive integer)\n"
+ "Example: " + COMMAND_WORD + " 1";

public static final String MESSAGE_DELETE_SCHEDULE_SUCCESS = "Deleted Schedule: %1$s";

private final Index targetIndex;

/**
* Create {@code DeleteScheduleCommand} with target index to delete.
*
* @param targetIndex Target index of schedule to delete.
*/
public DeleteScheduleCommand(Index targetIndex) {
requireNonNull(targetIndex);
this.targetIndex = targetIndex;
}

/**
* Deletes schedule if exists in schedule list.
*
* @param model {@code Model} which the command should operate on.
* @return Command Result indicating success or failure of delete operation
* @throws CommandException
*/
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);

List<Schedule> lastShownList = model.getFilteredScheduleList();

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

Schedule scheduleToDelete = lastShownList.get(targetIndex.getZeroBased());
model.deleteSchedule(scheduleToDelete);
return new CommandResult(String.format(MESSAGE_DELETE_SCHEDULE_SUCCESS, scheduleToDelete));
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof DeleteScheduleCommand // instanceof handles nulls
&& targetIndex.equals(((DeleteScheduleCommand) other).targetIndex)); // state check
}
}
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/logic/parser/CliSyntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,11 @@ public class CliSyntax {
public static final Prefix PREFIX_TIME_FROM = new Prefix("fr/");
public static final Prefix PREFIX_TIME_TO = new Prefix("to/");
public static final Prefix PREFIX_LOCATION = new Prefix("l/");

/*
* Schedule prefix definitions
*/
public static final Prefix PREFIX_TITLE = new Prefix("t/");
public static final Prefix PREFIX_DESCRIPTION = new Prefix("ds/");

}
36 changes: 35 additions & 1 deletion src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
import seedu.address.model.schedule.Description;
import seedu.address.model.schedule.Title;
import seedu.address.model.subject.SubjectExperience;
import seedu.address.model.subject.SubjectLevel;
import seedu.address.model.subject.SubjectList;
Expand All @@ -36,6 +38,7 @@ public class ParserUtil {
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
*
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
Expand Down Expand Up @@ -230,7 +233,7 @@ public static SubjectQualification parseSubjectQualification(String subjectQuali
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the number of items in each {@code List} is not equal or
* if any items are invalid.
* if any items are invalid.
*/
public static SubjectList parseSubjectList(
List<String> subjectNames,
Expand Down Expand Up @@ -278,6 +281,7 @@ public static SubjectList parseSubjectList(
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
*
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static AppointmentDateTime parseDateTime(String dateTime) throws ParseException {
Expand All @@ -288,4 +292,34 @@ public static AppointmentDateTime parseDateTime(String dateTime) throws ParseExc
}
return new AppointmentDateTime(trimmedDateTime);
}

/**
* Parses a {@code String title} into a {@code Title}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code title} is invalid.
*/
public static Title parseTitle(String title) throws ParseException {
requireNonNull(title);
String trimmedTitle = title.trim();
if (!Title.isValidTitle(trimmedTitle)) {
throw new ParseException(Name.MESSAGE_CONSTRAINTS);
}
return new Title(trimmedTitle);
}

/**
* Parses a {@code String description} into a {@code Description}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code description} is invalid.
*/
public static Description parseDescription(String description) throws ParseException {
requireNonNull(description);
String trimmedDescription = description.trim();
if (!Description.isValidDescription(trimmedDescription)) {
throw new ParseException(Name.MESSAGE_CONSTRAINTS);
}
return new Description(trimmedDescription);
}
}
10 changes: 10 additions & 0 deletions src/main/java/seedu/address/logic/parser/TutorTrackerParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@
import seedu.address.logic.commands.appointmentcommands.FindAppointmentCommand;
import seedu.address.logic.commands.appointmentcommands.ListAppointmentCommand;
import seedu.address.logic.commands.appointmentcommands.ViewAppointmentCommand;
import seedu.address.logic.commands.schedulecommands.AddScheduleCommand;
import seedu.address.logic.commands.schedulecommands.DeleteScheduleCommand;
import seedu.address.logic.parser.appointmentparser.AddAppointmentCommandParser;
import seedu.address.logic.parser.appointmentparser.DeleteAppointmentCommandParser;
import seedu.address.logic.parser.appointmentparser.EditAppointmentCommandParser;
import seedu.address.logic.parser.appointmentparser.FindAppointmentCommandParser;
import seedu.address.logic.parser.appointmentparser.ViewAppointmentCommandParser;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.logic.parser.scheduleparser.AddScheduleCommandParser;
import seedu.address.logic.parser.scheduleparser.DeleteScheduleCommandParser;

/**
* Parses user input.
Expand Down Expand Up @@ -110,6 +114,12 @@ public Command parseCommand(String userInput) throws ParseException {
case ListAppointmentCommand.COMMAND_WORD:
return new ListAppointmentCommand();

/* Schedule Commands */
case AddScheduleCommand.COMMAND_WORD:
return new AddScheduleCommandParser().parse(arguments);
case DeleteScheduleCommand.COMMAND_WORD:
return new DeleteScheduleCommandParser().parse(arguments);

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package seedu.address.logic.parser.scheduleparser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME_FROM;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME_TO;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TITLE;

import seedu.address.logic.commands.schedulecommands.AddScheduleCommand;
import seedu.address.logic.parser.ArgumentMultimap;
import seedu.address.logic.parser.ArgumentTokenizer;
import seedu.address.logic.parser.Parser;
import seedu.address.logic.parser.ParserUtil;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.appointment.AppointmentDateTime;
import seedu.address.model.schedule.Description;
import seedu.address.model.schedule.Schedule;
import seedu.address.model.schedule.Title;

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

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

if (!ArgumentTokenizer.arePrefixesPresent(argMultimap, PREFIX_TITLE, PREFIX_DATE, PREFIX_TIME_FROM,
PREFIX_TIME_TO, PREFIX_DESCRIPTION) || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(
MESSAGE_INVALID_COMMAND_FORMAT, AddScheduleCommand.MESSAGE_USAGE));
}

Title title = ParserUtil.parseTitle(argMultimap.getValue(PREFIX_TITLE).get());
String dateString = argMultimap.getValue(PREFIX_DATE).get();
String timeFromString = argMultimap.getValue(PREFIX_TIME_FROM).get();
String timeToString = argMultimap.getValue(PREFIX_TIME_TO).get();
AppointmentDateTime timeFrom = ParserUtil.parseDateTime(dateString + " " + timeFromString);
AppointmentDateTime timeTo = ParserUtil.parseDateTime(dateString + " " + timeToString);
Description description = ParserUtil.parseDescription(argMultimap.getValue(PREFIX_DESCRIPTION).get());

Schedule schedule = new Schedule(title, timeFrom, timeTo, description);

return new AddScheduleCommand(schedule);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package seedu.address.logic.parser.scheduleparser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.schedulecommands.DeleteScheduleCommand;
import seedu.address.logic.parser.Parser;
import seedu.address.logic.parser.ParserUtil;
import seedu.address.logic.parser.exceptions.ParseException;

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

/**
* Parses the given {@code String} of arguments in the context of the DeleteScheduleCommand
* and returns a DeleteScheduleCommand object for execution.
*
* @throws ParseException if the user input does not conform the expected format
*/
public DeleteScheduleCommand parse(String args) throws ParseException {
try {
Index index = ParserUtil.parseIndex(args);
return new DeleteScheduleCommand(index);
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteScheduleCommand.MESSAGE_USAGE), pe);
}
}

}
4 changes: 3 additions & 1 deletion src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import seedu.address.model.appointment.Appointment;
import seedu.address.model.appointment.AppointmentDateTime;
import seedu.address.model.person.Person;
import seedu.address.model.schedule.ScheduleModel;

/**
* The API of the Model component.
*/
public interface Model {
public interface Model extends ScheduleModel {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am slightly concerned about having Model extend ScheduleModel in terms of design, but I understand why it's done this way for abstraction and to maintain compatibility. If there is no better solution then it LGTM. Perhaps in a future PR we can abstract the different model interfaces out (for tutor, appointment, etc) and then have Model extend all of them for consistency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, then I'll shift it back to Model for meantime. If we decided to adopt this approach then I'll reinstate back in this file

/**
* {@code Predicate} that always evaluate to true
*/
Expand Down Expand Up @@ -74,6 +75,7 @@ public interface Model {

/**
* Sets appointment book file path.
*
* @param appointmentBookFilePath To be supplied by user
*/
void setAppointmentBookFilePath(Path appointmentBookFilePath);
Expand Down
Loading