diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index 8a3726d8e78..a411fa32d7c 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -18,6 +18,8 @@ public class Messages { public static final String MESSAGE_STUDENTS_LISTED_OVERVIEW = "%1$d students listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = "Multiple values specified for the following single-valued field(s): "; + public static final String MESSAGE_DUPLICATE_LESSON = "This lesson already exists in the student's lesson list"; + public static final String MESSAGE_INVALID_LESSON = "The lesson does not exist for the specified student"; /** * Returns an error message indicating the duplicate prefixes. diff --git a/src/main/java/seedu/address/logic/commands/AddLessonCommand.java b/src/main/java/seedu/address/logic/commands/AddLessonCommand.java index 0b3485bb140..4eda67bd41d 100644 --- a/src/main/java/seedu/address/logic/commands/AddLessonCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddLessonCommand.java @@ -63,11 +63,19 @@ public CommandResult execute(Model model) throws CommandException { Student studentToEdit = lastShownList.get(index.getZeroBased()); List lessonList = new ArrayList<>(studentToEdit.getLessons()); String studentToEditSubject = studentToEdit.getSubject().value; + // Separate lesson constructors if isCompleted parameter is provided from user input. + Lesson newLesson; if (isCompleted != null) { - lessonList.add(new Lesson(studentToEditSubject, this.date, this.time, this.isCompleted)); + newLesson = new Lesson(studentToEditSubject, this.date, this.time, this.isCompleted); } else { - lessonList.add(new Lesson(studentToEditSubject, this.date, this.time)); + newLesson = new Lesson(studentToEditSubject, this.date, this.time); } + // Check if the lesson already exists in the student's lesson list. + if (lessonList.contains(newLesson)) { + throw new CommandException(Messages.MESSAGE_DUPLICATE_LESSON); + } + // Add the lesson to the student's lesson list. + lessonList.add(newLesson); Student editedStudent = new Student(studentToEdit.getName(), studentToEdit.getPhone(), studentToEdit.getEmail(), studentToEdit.getAddress(), studentToEdit.getSubject(), studentToEdit.getRemark(), lessonList); diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 94a3fde9ed5..339d4ad1ef7 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -6,6 +6,7 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_LESSON; 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_SUBJECT; import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS; import java.util.List; @@ -42,7 +43,8 @@ public class EditCommand extends Command { + "[" + PREFIX_PHONE + "PHONE] " + "[" + PREFIX_EMAIL + "EMAIL] " + "[" + PREFIX_ADDRESS + "ADDRESS] " - + "[" + PREFIX_LESSON + "TAG]...\n" + + "[" + PREFIX_SUBJECT + "SUBJECT] " + + "[" + PREFIX_LESSON + "LESSON]...\n" + "Example: " + COMMAND_WORD + " 1 " + PREFIX_PHONE + "91234567 " + PREFIX_EMAIL + "johndoe@example.com"; diff --git a/src/main/java/seedu/address/logic/commands/MarkLessonCommand.java b/src/main/java/seedu/address/logic/commands/MarkLessonCommand.java new file mode 100644 index 00000000000..04235024037 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/MarkLessonCommand.java @@ -0,0 +1,79 @@ +package seedu.address.logic.commands; + +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +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.student.Lesson; +import seedu.address.model.student.Student; + +/** + * Marks a lesson as done for a student. + */ +public class MarkLessonCommand extends Command { + public static final String COMMAND_WORD = "mark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks a lesson as completed to the student identified " + + "by the index number used in the last person listing. " + + "Parameters: INDEX (must be a positive integer) " + + "l/ [LESSON]\n" + + "Example: " + COMMAND_WORD + " 1 " + + "l/ 20-02-2002|10:00"; + + public static final String MESSAGE_MARK_LESSON_SUCCESS = "Mark lesson %1$s to student: %1$s"; + private final Index index; + private final LocalDate dateDetail; + private final LocalTime timeDetail; + /** + * Creates a MarkLessonDoneCommand to mark the specified {@code Lesson} as done. + */ + public MarkLessonCommand(Index index, LocalDate dateDetail, LocalTime timeDetail) { + this.index = index; + this.dateDetail = dateDetail; + this.timeDetail = timeDetail; + } + @Override + public CommandResult execute(Model model) throws CommandException { + List lastShownList = model.getFilteredStudentList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX); + } + + Student studentToEdit = lastShownList.get(index.getZeroBased()); + List lessonList = new ArrayList<>(studentToEdit.getLessons()); + String studentToEditSubject = studentToEdit.getSubject().value; + + Lesson lessonToMarkDone = new Lesson(studentToEditSubject, dateDetail, timeDetail); + // Iterate through lessonList and check if lessonToMark is found in list. + Boolean lessonFound = false; + for (Lesson l : lessonList) { + if (l.equals(lessonToMarkDone)) { + l.setLessonComplete(); + lessonFound = true; + break; + } + } + // throw exception if lesson is not found in list. + if (!lessonFound) { + throw new CommandException(Messages.MESSAGE_INVALID_LESSON); + } + Student editedStudent = new Student(studentToEdit.getName(), studentToEdit.getPhone(), studentToEdit.getEmail(), + studentToEdit.getAddress(), studentToEdit.getSubject(), + studentToEdit.getRemark(), lessonList); + + model.setStudent(studentToEdit, editedStudent); + model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS); + + return new CommandResult(String.format(MESSAGE_MARK_LESSON_SUCCESS, + lessonToMarkDone.getLessonValue(), Messages.format(editedStudent))); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddLessonCommandParser.java b/src/main/java/seedu/address/logic/parser/AddLessonCommandParser.java index b315a0a1845..74d223f5769 100644 --- a/src/main/java/seedu/address/logic/parser/AddLessonCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddLessonCommandParser.java @@ -60,7 +60,7 @@ public AddLessonCommand parse(String args) throws ParseException { * @param lesson the lesson to be checked * @return true if the lesson is in the correct format, false otherwise */ - public boolean isValidLesson(String lesson) { + public static boolean isValidLesson(String lesson) { String[] lessonDetails = lesson.trim().split("\\|"); if (lessonDetails.length != 2 && lessonDetails.length != 3) { return false; diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index dcd77a670f5..7923ddd7c40 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -18,6 +18,7 @@ import seedu.address.logic.commands.FindCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.MarkLessonCommand; import seedu.address.logic.commands.RemarkCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -85,6 +86,9 @@ public Command parseCommand(String userInput) throws ParseException { case AddLessonCommand.COMMAND_WORD: return new AddLessonCommandParser().parse(arguments); + case MarkLessonCommand.COMMAND_WORD: + return new MarkLessonCommandParser().parse(arguments); + default: logger.finer("This user input caused a ParseException: " + userInput); diff --git a/src/main/java/seedu/address/logic/parser/MarkLessonCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkLessonCommandParser.java new file mode 100644 index 00000000000..ab2afabef24 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/MarkLessonCommandParser.java @@ -0,0 +1,54 @@ +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.AddLessonCommandParser.isValidLesson; +import static seedu.address.logic.parser.CliSyntax.PREFIX_LESSON; +import static seedu.address.model.student.Lesson.DATE_FORMATTER; +import static seedu.address.model.student.Lesson.TIME_FORMATTER; + +import java.time.LocalDate; +import java.time.LocalTime; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.logic.commands.MarkLessonCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new MarkLessonCommand object + */ +public class MarkLessonCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the MarkLessonCommand + * and returns an MarkLessonCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + @Override + public MarkLessonCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_LESSON); + + Index index; + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MarkLessonCommand.MESSAGE_USAGE), ive); + } + + String lesson = argMultimap.getValue(PREFIX_LESSON).orElse(""); + + if (!isValidLesson(lesson)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MarkLessonCommand.MESSAGE_USAGE)); + } + // split lesson into its attributes based on "|" character + String[] lessonDetails = lesson.trim().split("\\|"); + LocalDate dateDetail = LocalDate.parse(lessonDetails[0], DATE_FORMATTER); + LocalTime timeDetail = LocalTime.parse(lessonDetails[1], TIME_FORMATTER); + + return new MarkLessonCommand(index, dateDetail, timeDetail); + } +} diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 207cbec6d50..e073c95f720 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -124,7 +124,7 @@ public static Subject parseSubject(String subject) throws ParseException { public static Lesson parseLesson(String lesson) throws ParseException { requireNonNull(lesson); if (!isValidLesson(lesson) && !isValidJsonLesson(lesson)) { - throw new ParseException(Lesson.MESSAGE_CONSTRAINTS); + throw new ParseException(Lesson.MESSAGE_CONSTRAINTS_1); } // split lesson into its attributes based on "|" character String[] lessonDetails = lesson.trim().split("\\|"); diff --git a/src/main/java/seedu/address/model/student/Lesson.java b/src/main/java/seedu/address/model/student/Lesson.java index c42254613bc..23939f7541d 100644 --- a/src/main/java/seedu/address/model/student/Lesson.java +++ b/src/main/java/seedu/address/model/student/Lesson.java @@ -13,9 +13,12 @@ * Guarantees: details are present and not null, field values are validated, immutable. */ public class Lesson { - public static final String MESSAGE_CONSTRAINTS = + public static final String MESSAGE_CONSTRAINTS_1 = "Lessons must be of the form subject|dd-MM-yyyy|hh:mm|0/1, where subject contains only alphabeths" + " and spaces, and indicate lesson incomplete/completed with 0 or 1 respectively."; + public static final String MESSAGE_CONSTRAINTS_2 = + "Lessons must be of the form dd-MM-yyyy|hh:mm OR dd-MM-yyyy|hh:mm|0/1, where the last field of 0 or 1" + + " is optional, with 0 indicating lesson incomplete and 1 indicating lesson complete."; public static final String VALIDATION_REGEX = "^[a-zA-Z][a-zA-Z ]*$"; public static final String DATE_REGEX = "\\d{2}-\\d{2}-\\d{4}"; public static final String TIME_REGEX = "\\d{2}:\\d{2}"; @@ -39,7 +42,7 @@ public Lesson(String subject, LocalDate date, LocalTime time) { requireNonNull(subject); requireNonNull(date); requireNonNull(time); - checkArgument(subject.matches(VALIDATION_REGEX), MESSAGE_CONSTRAINTS); + checkArgument(subject.matches(VALIDATION_REGEX), MESSAGE_CONSTRAINTS_1); // assign the attributes to the lesson this.subject = new Subject(subject); this.date = LocalDate.parse(date.format(DATE_FORMATTER), DATE_FORMATTER); diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java index 23f38cb1292..aa49ca1ef5a 100644 --- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java @@ -193,7 +193,7 @@ public void parse_invalidValue_failure() { // invalid lesson assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB - + SUBJECT_DESC_MATHS + INVALID_LESSON_DESC, Lesson.MESSAGE_CONSTRAINTS); + + SUBJECT_DESC_MATHS + INVALID_LESSON_DESC, Lesson.MESSAGE_CONSTRAINTS_1); // two invalid values, only first invalid value reported assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java index b7221d62153..1b8a1f688d5 100644 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java @@ -89,7 +89,7 @@ public void parse_invalidValue_failure() { assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address - assertParseFailure(parser, "1" + INVALID_LESSON_DESC, Lesson.MESSAGE_CONSTRAINTS); // invalid lesson + assertParseFailure(parser, "1" + INVALID_LESSON_DESC, Lesson.MESSAGE_CONSTRAINTS_1); // invalid lesson // invalid phone followed by valid email assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS);