diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 0de5673070d..c3fd832fdef 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -12,14 +12,21 @@ Class AddressBook Class ModelManager Class UserPrefs +Class ModuleCode +Class ModuleContainsKeywordPredicate +Class ModuleTutorialPair +Class TutorialClass +Class TutorialContainsKeywordPredicate +Class Tag + Class UniquePersonList Class Person -Class Address -Class Email Class Name -Class Phone -Class Tag - +Class Email +Class StudentId +Class NameContainsKeywordPredicate +Class EmailContainsKeywordPredicate +Class StudentIdContainsKeywordPredicate Class I #FFFFFF } @@ -35,20 +42,27 @@ ModelManager -left-> "1" AddressBook ModelManager -right-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs +ModelManager *-left> "~* filtered" ModuleCode +AddressBook -left> "~* all" ModuleCode +ModuleCode -up> TutorialClass +ModuleTutorialPair -> ModuleCode +ModuleTutorialPair -down> TutorialClass +ModuleContainsKeywordPredicate -..down> ModuleCode +TutorialContainsKeywordPredicate -..up> TutorialClass +TutorialClass -> Person + AddressBook *--> "1" UniquePersonList UniquePersonList --> "~* all" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag - +Person *--> "1" Name +Person *--> "1" Email +Person *--> "1" StudentId +Person *--> Tag Person -[hidden]up--> I UniquePersonList -[hidden]right-> I -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email +NameContainsKeywordPredicate -..> Name +StudentIdContainsKeywordPredicate -left..> StudentId +EmailContainsKeywordPredicate -right..> Email ModelManager --> "~* filtered" Person @enduml diff --git a/src/main/java/seedu/address/logic/commands/DeleteModuleCommand.java b/src/main/java/seedu/address/logic/commands/DeleteModuleCommand.java new file mode 100644 index 00000000000..ba4725fa9a4 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteModuleCommand.java @@ -0,0 +1,74 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.address.logic.messages.ModuleMessages.MESSAGE_DELETE_MODULE_SUCCESS; +import static seedu.address.logic.messages.ModuleMessages.MESSAGE_MODULE_NOT_FOUND; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULECODE; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; + +/** + * A class used to handle the deletion of tutorial classes. + */ +public class DeleteModuleCommand extends Command { + + public static final String COMMAND_WORD = "/delete_module"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes a module with the module code specified\n" + + "Parameters:" + PREFIX_MODULECODE + "MODULE_CODE\n" + + "Example: " + COMMAND_WORD + " " + PREFIX_MODULECODE + " CS2103T"; + + private final ModuleCode module; + + /** + * Constructs a DeleteClassCommand to delete the specified {@code TutorialClass} + * from the specified {@code ModuleCode}. + * @param module The module code of the tutorial class to be deleted. + */ + public DeleteModuleCommand(ModuleCode module) { + requireAllNonNull(module); + this.module = module; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + ModuleCode existingModule = model.findModuleFromList(module); + if (existingModule == null) { + String moduleNotFoundMessage = String.format(MESSAGE_MODULE_NOT_FOUND, module); + throw new CommandException(moduleNotFoundMessage); + } else { + model.deleteModule(existingModule); + } + return new CommandResult(generateSuccessMessage(module)); + } + + /** + * Generates a command execution success message based on whether the tutorial class is successfully deleted. + * @param module The module code of the tutorial class. + * @return The success message. + */ + private String generateSuccessMessage(ModuleCode module) { + return String.format(MESSAGE_DELETE_MODULE_SUCCESS, module.toString()); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof DeleteModuleCommand)) { + return false; + } + + DeleteModuleCommand e = (DeleteModuleCommand) other; + return module.equals(e.module); + } +} diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 90f559fb985..e2484c74cf8 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -2,6 +2,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INDEX; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_STUDENTID; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; @@ -31,23 +32,26 @@ */ public class EditCommand extends Command { - public static final String COMMAND_WORD = "edit"; + public static final String COMMAND_WORD = "/edit_student"; public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified " + "by the index number used in the displayed person list. " + "Existing values will be overwritten by the input values.\n" - + "Parameters: INDEX (must be a positive integer) " + + "Parameters: " + + PREFIX_INDEX + "INDEX (must be a positive integer) " + "[" + PREFIX_NAME + "NAME] " - + "[" + PREFIX_STUDENTID + "PHONE] " + + "[" + PREFIX_STUDENTID + "STUDENT ID] " + "[" + PREFIX_EMAIL + "EMAIL] " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " 1 " - + PREFIX_STUDENTID + "91234567 " + + PREFIX_STUDENTID + "A1234567Z " + PREFIX_EMAIL + "johndoe@example.com"; public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s"; public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book."; + public static final String MESSAGE_DUPLICATE_EMAIL = "This email already exists in the address book."; + public static final String MESSAGE_DUPLICATE_STUDENTID = "This student id already exists in the address book."; private final Index index; private final EditPersonDescriptor editPersonDescriptor; @@ -80,6 +84,16 @@ public CommandResult execute(Model model) throws CommandException { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } + Optional emailToBeEdited = editPersonDescriptor.getEmail(); + if (emailToBeEdited.isPresent() && model.hasPersonWithEmail(emailToBeEdited.get())) { + throw new CommandException(MESSAGE_DUPLICATE_EMAIL); + } + + Optional studentIdToBeEdited = editPersonDescriptor.getStudentId(); + if (studentIdToBeEdited.isPresent() && model.hasPersonWithStudentId(studentIdToBeEdited.get())) { + throw new CommandException(MESSAGE_DUPLICATE_STUDENTID); + } + model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson))); diff --git a/src/main/java/seedu/address/logic/commands/SortStudentCommand.java b/src/main/java/seedu/address/logic/commands/SortStudentCommand.java new file mode 100644 index 00000000000..31bd6b17c94 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/SortStudentCommand.java @@ -0,0 +1,81 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.parser.CliSyntax.PREFIX_SORT_BY; + +import java.util.Comparator; + +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Person; + +/** + * Sorts students information lexicographically based on given parameter + */ +public class SortStudentCommand extends Command { + + public static final String COMMAND_WORD = "/sort_student"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sorts students based on specified parameter.\n" + + "Parameters: " + + PREFIX_SORT_BY + "name " + "or " + + PREFIX_SORT_BY + "id " + "or " + + PREFIX_SORT_BY + "email\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_SORT_BY + "name"; + + public static final String MESSAGE_SORT_STUDENT_SUCCESS = "Students have been successfully sorted"; + public static final String MESSAGE_INVALID_PARAMETER = "Not a valid parameter for sorting."; + public static final String MESSAGE_EMPTY_PARAMETER = "Please provide a parameter."; + + private final String sortBy; + public SortStudentCommand(String sortBy) { + this.sortBy = sortBy; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + Comparator personComparator; + switch (sortBy) { + case "name": + personComparator = Comparator.comparing(p -> p.getName().toString()); + break; + case "id": + personComparator = Comparator.comparing(p -> p.getStudentId().toString()); + break; + case "email": + personComparator = Comparator.comparing(p -> p.getEmail().toString()); + break; + case "": + throw new CommandException(String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_USAGE)); + default: + throw new CommandException(MESSAGE_INVALID_PARAMETER); + } + + model.getSortedPersonList(personComparator); + return new CommandResult(MESSAGE_SORT_STUDENT_SUCCESS); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof SortStudentCommand)) { + return false; + } + + SortStudentCommand otherSortStudentCommand = (SortStudentCommand) other; + return sortBy.equals(otherSortStudentCommand.sortBy); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("sortBy", sortBy) + .toString(); + } +} diff --git a/src/main/java/seedu/address/logic/commands/addstudenttoclasscommands/AddStudentToClassByIndexCommand.java b/src/main/java/seedu/address/logic/commands/addstudenttoclasscommands/AddStudentToClassByIndexCommand.java index 283be417bdd..3ae352cbfcb 100644 --- a/src/main/java/seedu/address/logic/commands/addstudenttoclasscommands/AddStudentToClassByIndexCommand.java +++ b/src/main/java/seedu/address/logic/commands/addstudenttoclasscommands/AddStudentToClassByIndexCommand.java @@ -65,7 +65,7 @@ public boolean equals(Object other) { return true; } - if (!(other instanceof AddStudentToClassByIdCommand)) { + if (!(other instanceof AddStudentToClassByIndexCommand)) { return false; } diff --git a/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByEmailCommand.java b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByEmailCommand.java new file mode 100644 index 00000000000..c56a36050b2 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByEmailCommand.java @@ -0,0 +1,80 @@ +package seedu.address.logic.commands.deletestudentfromclasscommands; + +import static java.util.Objects.requireNonNull; + +import java.util.function.Predicate; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.logic.messages.PersonMessages; +import seedu.address.logic.messages.TutorialClassMessages; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTutorialPair; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; +import seedu.address.model.person.Person; + +/** + * Deletes a student from a specified tutorial class, by identifying + * the student via their email. + */ +public class DeleteStudentFromClassByEmailCommand extends DeleteStudentFromClassCommand { + private final Predicate predicate; + + private final Email email; + + /** + * Deletes a student from a class by email. + * @param email + * @param module + * @param tutorialClass + */ + public DeleteStudentFromClassByEmailCommand(Email email, ModuleCode module, TutorialClass tutorialClass) { + super(module, tutorialClass); + this.email = email; + this.predicate = person -> person.getEmail().equals(email); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + ModuleTutorialPair moduleAndTutorialClass = getModuleAndTutorialClass(model); + TutorialClass tutorialClass = moduleAndTutorialClass.getTutorialClass(); + ModuleCode module = moduleAndTutorialClass.getModule(); + Person personToDelete; + + personToDelete = model.searchPersonByPredicate(predicate); + if (personToDelete == null) { + throw new CommandException(String.format(PersonMessages.MESSAGE_PERSON_EMAIL_NOT_FOUND, email)); + } + if (!(tutorialClass.hasStudent(personToDelete))) { + throw new CommandException( + String.format(TutorialClassMessages.MESSAGE_STUDENT_NOT_FOUND_IN_CLASS, + Messages.format(personToDelete), tutorialClass)); + } else { + model.deletePersonFromTutorialClass(personToDelete, module, tutorialClass); + return new CommandResult( + String.format(TutorialClassMessages.MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS, + Messages.format(personToDelete), module, tutorialClass)); + } + } + + /** + * Returns true if both DeleteStudentFromClassByEmailCommand have the same email. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof DeleteStudentFromClassByEmailCommand)) { + return false; + } + + DeleteStudentFromClassByEmailCommand otherDeleteCommand = (DeleteStudentFromClassByEmailCommand) other; + return email.equals(otherDeleteCommand.email); + } +} diff --git a/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIdCommand.java b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIdCommand.java new file mode 100644 index 00000000000..cffff4e9438 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIdCommand.java @@ -0,0 +1,78 @@ +package seedu.address.logic.commands.deletestudentfromclasscommands; + +import static java.util.Objects.requireNonNull; + +import java.util.function.Predicate; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.logic.messages.PersonMessages; +import seedu.address.logic.messages.TutorialClassMessages; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTutorialPair; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; + +/** + * Deletes a student from a specified tutorial class, by identifying + * the student via their Student ID. + */ +public class DeleteStudentFromClassByIdCommand extends DeleteStudentFromClassCommand { + + private final Predicate predicate; + + private final StudentId studentId; + + /** + * Deletes a student from a class by student id. + * @param studentId + * @param module + * @param tutorialClass + */ + public DeleteStudentFromClassByIdCommand(StudentId studentId, ModuleCode module, TutorialClass tutorialClass) { + super(module, tutorialClass); + this.studentId = studentId; + this.predicate = person -> person.getStudentId().equals(studentId); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + ModuleTutorialPair moduleAndTutorialClass = getModuleAndTutorialClass(model); + ModuleCode module = moduleAndTutorialClass.getModule(); + TutorialClass tutorialClass = moduleAndTutorialClass.getTutorialClass(); + Person personToDelete; + personToDelete = model.searchPersonByPredicate(predicate); + if (personToDelete == null) { + throw new CommandException(String.format(PersonMessages.MESSAGE_PERSON_STUDENT_ID_NOT_FOUND, studentId)); + } + if (!(tutorialClass.hasStudent(personToDelete))) { + throw new CommandException(String.format(TutorialClassMessages.MESSAGE_STUDENT_NOT_FOUND_IN_CLASS, + Messages.format(personToDelete), tutorialClass)); + } else { + model.deletePersonFromTutorialClass(personToDelete, module, tutorialClass); + return new CommandResult(String.format(PersonMessages.MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS, + Messages.format(personToDelete), module, tutorialClass)); + } + } + + /** + * Returns true if both DeleteStudentFromClassByIdCommand have the same studentId. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof DeleteStudentFromClassByIdCommand)) { + return false; + } + + DeleteStudentFromClassByIdCommand otherDeleteCommand = (DeleteStudentFromClassByIdCommand) other; + return studentId.equals(otherDeleteCommand.studentId); + } +} diff --git a/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIndexCommand.java b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIndexCommand.java new file mode 100644 index 00000000000..b9a558b6b0d --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassByIndexCommand.java @@ -0,0 +1,77 @@ +package seedu.address.logic.commands.deletestudentfromclasscommands; + +import static java.util.Objects.requireNonNull; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.logic.messages.PersonMessages; +import seedu.address.logic.messages.TutorialClassMessages; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTutorialPair; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Person; + + +/** + * Deletes a student from a specified tutorial class, by identifying + * the student via their index. + */ +public class DeleteStudentFromClassByIndexCommand extends DeleteStudentFromClassCommand { + private final Index targetIndex; + + /** + * Deletes a student from a class by index. + * @param targetIndex + * @param module + * @param tutorialClass + */ + public DeleteStudentFromClassByIndexCommand(Index targetIndex, ModuleCode module, TutorialClass tutorialClass) { + super(module, tutorialClass); + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + ModuleTutorialPair moduleAndTutorialClass = getModuleAndTutorialClass(model); + TutorialClass tutorialClass = moduleAndTutorialClass.getTutorialClass(); + ModuleCode module = moduleAndTutorialClass.getModule(); + Person personToDelete; + try { + personToDelete = model.getFilteredPersonList().get(targetIndex.getZeroBased()); + } catch (IndexOutOfBoundsException e) { + throw new CommandException( + String.format(PersonMessages.MESSAGE_PERSON_INDEX_NOT_FOUND, targetIndex.getOneBased())); + } + + if (!(tutorialClass.hasStudent(personToDelete))) { + throw new CommandException(String.format(TutorialClassMessages.MESSAGE_STUDENT_NOT_FOUND_IN_CLASS, + Messages.format(personToDelete), tutorialClass)); + } else { + model.deletePersonFromTutorialClass(personToDelete, module, tutorialClass); + return new CommandResult( + String.format(PersonMessages.MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS, + Messages.format(personToDelete), module, tutorialClass)); + } + } + + /** + * Returns true if both DeleteStudentFromClassByIndexCommand have the same index. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof DeleteStudentFromClassByIndexCommand)) { + return false; + } + + DeleteStudentFromClassByIndexCommand otherDeleteCommand = (DeleteStudentFromClassByIndexCommand) other; + return targetIndex.equals(otherDeleteCommand.targetIndex); + } +} diff --git a/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassCommand.java b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassCommand.java new file mode 100644 index 00000000000..f8ca13b1a25 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/deletestudentfromclasscommands/DeleteStudentFromClassCommand.java @@ -0,0 +1,69 @@ +package seedu.address.logic.commands.deletestudentfromclasscommands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULECODE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIALCLASS; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.logic.messages.ModuleMessages; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTutorialPair; +import seedu.address.model.module.TutorialClass; + +/** + * The abstract class that handles all delete student from tutorial class commands. + */ +public abstract class DeleteStudentFromClassCommand extends Command { + public static final String COMMAND_WORD = "/delete_student_from_class"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes a student from an existing class\n" + + "Parameters:" + "IDENTIFIER " + PREFIX_MODULECODE + "MODULE_CODE (must be a String) " + + PREFIX_TUTORIALCLASS + "TUTORIAL_CLASS (must be a String)\n" + + "Example: " + COMMAND_WORD + " " + PREFIX_EMAIL + "test@gmail.com " + PREFIX_MODULECODE + " CS2103T " + + PREFIX_TUTORIALCLASS + "T09"; + + private final ModuleCode module; + private final TutorialClass tutorialClass; + + /** + * @param module of the tutorial class to be added + */ + public DeleteStudentFromClassCommand(ModuleCode module, TutorialClass tutorialClass) { + requireAllNonNull(module, tutorialClass); + this.module = module; + this.tutorialClass = tutorialClass; + } + + protected ModuleTutorialPair getModuleAndTutorialClass(Model model) throws CommandException { + requireNonNull(model); + ModuleCode module = getModule(); + TutorialClass tutorialClass = getTutorialClass(); + ModuleCode existingModule = model.findModuleFromList(module); + TutorialClass existingTutorialClass = model.findTutorialClassFromList(tutorialClass, existingModule); + if (existingModule == null) { + throw new CommandException(String.format(ModuleMessages.MESSAGE_MODULE_NOT_FOUND, module)); + } + if (existingTutorialClass == null) { + throw new CommandException( + String.format(ModuleMessages.MESSAGE_TUTORIAL_DOES_NOT_BELONG_TO_MODULE, tutorialClass, module)); + } + return new ModuleTutorialPair(existingModule, existingTutorialClass); + } + + protected ModuleCode getModule() { + return module; + } + + protected TutorialClass getTutorialClass() { + return tutorialClass; + } + + public abstract CommandResult execute(Model model) throws CommandException; + + public abstract boolean equals(Object other); +} diff --git a/src/main/java/seedu/address/logic/messages/ModuleMessages.java b/src/main/java/seedu/address/logic/messages/ModuleMessages.java index c73bf1ec2f1..e3824abda33 100644 --- a/src/main/java/seedu/address/logic/messages/ModuleMessages.java +++ b/src/main/java/seedu/address/logic/messages/ModuleMessages.java @@ -8,4 +8,6 @@ public class ModuleMessages { + "does not exist in the address book"; public static final String MESSAGE_TUTORIAL_DOES_NOT_BELONG_TO_MODULE = "The tutorial class with tutorial code %s " + "does not belong to the module with module code %s"; + + public static final String MESSAGE_DELETE_MODULE_SUCCESS = "Removed %1$s!"; } diff --git a/src/main/java/seedu/address/logic/messages/PersonMessages.java b/src/main/java/seedu/address/logic/messages/PersonMessages.java index f3c2061b8ea..3035ca43a05 100644 --- a/src/main/java/seedu/address/logic/messages/PersonMessages.java +++ b/src/main/java/seedu/address/logic/messages/PersonMessages.java @@ -11,5 +11,7 @@ public class PersonMessages { public static final String MESSAGE_PERSON_INDEX_NOT_FOUND = "The student at index %s " + "does not exist in the address book"; public static final String MESSAGE_ADD_STUDENT_TO_CLASS_SUCCESS = "Added student %1$s to %2$s %3$s"; + + public static final String MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS = "Deleted student %1$s from %2$s %3$s"; public static final String MESSAGE_DUPLICATE_STUDENT_IN_CLASS = "%1$s already added to %2$s!"; } diff --git a/src/main/java/seedu/address/logic/messages/TutorialClassMessages.java b/src/main/java/seedu/address/logic/messages/TutorialClassMessages.java index 529b9d0b15a..cfc54fdc2af 100644 --- a/src/main/java/seedu/address/logic/messages/TutorialClassMessages.java +++ b/src/main/java/seedu/address/logic/messages/TutorialClassMessages.java @@ -7,5 +7,7 @@ public class TutorialClassMessages { public static final String MESSAGE_TUTORIAL_CLASS_NOT_FOUND = "The tutorial class with tutorial class code %s " + "does not exist in the address book"; public static final String MESSAGE_DUPLICATE_STUDENT_IN_CLASS = "%1$s already added to %2$s!"; + public static final String MESSAGE_STUDENT_NOT_FOUND_IN_CLASS = "%1$s is not in %2$s!"; public static final String MESSAGE_ADD_STUDENT_TO_CLASS_SUCCESS = "Added student %1$s to %2$s %3$s"; + public static final String MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS = "Deleted student %1$s from %2$s %3$s"; } diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 01323b5fb66..ddeb4644468 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -15,6 +15,7 @@ import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteClassCommand; import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.DeleteModuleCommand; import seedu.address.logic.commands.DeleteTeamCommand; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; @@ -23,8 +24,10 @@ import seedu.address.logic.commands.ListStudentsCommand; import seedu.address.logic.commands.ListStudentsOfClassCommand; import seedu.address.logic.commands.SearchStudentCommand; +import seedu.address.logic.commands.SortStudentCommand; import seedu.address.logic.commands.addstudenttoclasscommands.AddStudentToClassCommand; import seedu.address.logic.commands.deletestudentcommands.DeleteStudentCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassCommand; import seedu.address.logic.parser.exceptions.ParseException; /** @@ -77,6 +80,9 @@ public Command parseCommand(String userInput) throws ParseException { case DeleteClassCommand.COMMAND_WORD: return new DeleteClassCommandParser().parse(arguments); + case DeleteModuleCommand.COMMAND_WORD: + return new DeleteModuleCommandParser().parse(arguments); + case DeleteStudentCommand.COMMAND_WORD: return new DeleteStudentCommandParser().parse(arguments); @@ -101,11 +107,20 @@ public Command parseCommand(String userInput) throws ParseException { case AddStudentToClassCommand.COMMAND_WORD: return new AddStudentToClassCommandParser().parse(arguments); + case DeleteStudentFromClassCommand.COMMAND_WORD: + return new DeleteStudentFromClassCommandParser().parse(arguments); + case AddTeamCommand.COMMAND_WORD: return new AddTeamCommandParser().parse(arguments); + case ListStudentsOfClassCommand.COMMAND_WORD: return new ListStudentsOfClassCommandParser().parse(arguments); + + case SortStudentCommand.COMMAND_WORD: + return new SortStudentCommandParser().parse(arguments); + + case DeleteTeamCommand.COMMAND_WORD: return new DeleteTeamCommandParser().parse(arguments); default: diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index dda54cd045b..91e49401343 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -16,4 +16,5 @@ public class CliSyntax { public static final Prefix PREFIX_TAG = new Prefix("tag/"); public static final Prefix PREFIX_DESCRIPTION = new Prefix("description/"); public static final Prefix PREFIX_TEAM_SIZE = new Prefix("size/"); + public static final Prefix PREFIX_SORT_BY = new Prefix("by/"); } diff --git a/src/main/java/seedu/address/logic/parser/DeleteModuleCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteModuleCommandParser.java new file mode 100644 index 00000000000..67684b5d808 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/DeleteModuleCommandParser.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_MODULECODE; + +import java.util.stream.Stream; + +import seedu.address.logic.commands.DeleteModuleCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; + + + +/** + * Parses input arguments and creates a new {@code DeleteClassCommandParser} object + */ +public class DeleteModuleCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the {@code DeleteClassCommandParser} + * and returns a {@code DeleteClassCommandParser} object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteModuleCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_MODULECODE); + + if (!arePrefixesPresent(argMultimap, PREFIX_MODULECODE) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteModuleCommand.MESSAGE_USAGE)); + } + + String moduleCode = argMultimap.getValue(PREFIX_MODULECODE).orElse(""); + if (!(ModuleCode.isValidModuleCode(moduleCode))) { + throw new ParseException(ModuleCode.MESSAGE_CONSTRAINTS); + } + return new DeleteModuleCommand(new ModuleCode(moduleCode)); + } + /** + * Returns true if all the prefixes are present in the given {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} + diff --git a/src/main/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParser.java new file mode 100644 index 00000000000..1a7780dd258 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParser.java @@ -0,0 +1,76 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INDEX; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULECODE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_STUDENTID; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TUTORIALCLASS; + +import java.util.stream.Stream; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByEmailCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIdCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIndexCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; +import seedu.address.model.person.StudentId; + +/** + * Parses input arguments and creates a new DeleteStudentFromClassCommand object + */ +public class DeleteStudentFromClassCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the + * DeleteStudentFromClass and returns a DeleteStudentFromClassCommand object for + * execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteStudentFromClassCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_INDEX, PREFIX_EMAIL, PREFIX_STUDENTID, + PREFIX_MODULECODE, PREFIX_TUTORIALCLASS); + boolean isIndexPresent = argMultimap.getValue(PREFIX_INDEX).isPresent(); + boolean isEmailPresent = argMultimap.getValue(PREFIX_EMAIL).isPresent(); + boolean isStudentIdPresent = argMultimap.getValue(PREFIX_STUDENTID).isPresent(); + if (!arePrefixesPresent(argMultimap, PREFIX_MODULECODE, PREFIX_TUTORIALCLASS) || (!isIndexPresent + && !isEmailPresent && !isStudentIdPresent) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteStudentFromClassCommand.MESSAGE_USAGE)); + } + + argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_INDEX, PREFIX_STUDENTID, PREFIX_EMAIL, + PREFIX_MODULECODE, PREFIX_TUTORIALCLASS); + ModuleCode moduleCode = ParserUtil.parseModuleCode(argMultimap.getValue(PREFIX_MODULECODE).get()); + TutorialClass tutorialClass = ParserUtil.parseTutorialClass(argMultimap.getValue(PREFIX_TUTORIALCLASS).get()); + if (isIndexPresent) { + Index index = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_INDEX).get()); + return new DeleteStudentFromClassByIndexCommand(index, moduleCode, tutorialClass); + } else if (isStudentIdPresent) { + StudentId studentId = ParserUtil.parseStudentId(argMultimap.getValue(PREFIX_STUDENTID).get()); + return new DeleteStudentFromClassByIdCommand(studentId, moduleCode, tutorialClass); + } else if (isEmailPresent) { + Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); + return new DeleteStudentFromClassByEmailCommand(email, moduleCode, tutorialClass); + } else { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteStudentFromClassCommand.MESSAGE_USAGE)); + } + + } + + /** + * 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()); + } + +} diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java index f34cce07433..c2213f343eb 100644 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java @@ -3,6 +3,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INDEX; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_STUDENTID; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; @@ -31,17 +32,21 @@ public class EditCommandParser implements Parser { public EditCommand parse(String args) throws ParseException { requireNonNull(args); ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_EMAIL, PREFIX_STUDENTID, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_INDEX, PREFIX_NAME, PREFIX_EMAIL, PREFIX_STUDENTID, PREFIX_TAG); - Index index; + boolean isIndexPresent = argMultimap.getValue(PREFIX_INDEX).isPresent(); + if (!isIndexPresent) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + Index index; try { - index = ParserUtil.parseIndex(argMultimap.getPreamble()); + index = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_INDEX).get()); } catch (ParseException pe) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); } - argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_EMAIL, PREFIX_STUDENTID); + argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_INDEX, PREFIX_NAME, PREFIX_EMAIL, PREFIX_STUDENTID); EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor(); diff --git a/src/main/java/seedu/address/logic/parser/SortStudentCommandParser.java b/src/main/java/seedu/address/logic/parser/SortStudentCommandParser.java new file mode 100644 index 00000000000..758f201249d --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/SortStudentCommandParser.java @@ -0,0 +1,36 @@ +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_SORT_BY; + +import seedu.address.logic.commands.SortStudentCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new SortStudentCommand object + */ +public class SortStudentCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the SortStudentCommand + * and returns a SortStudentCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public SortStudentCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_SORT_BY); + + boolean isSortByPresent = argMultimap.getValue(PREFIX_SORT_BY).isPresent(); + + if (!isSortByPresent || !argMultimap.getPreamble().isEmpty() + || argMultimap.getValue(PREFIX_SORT_BY).get().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + } + + argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_SORT_BY); + + return new SortStudentCommand(argMultimap.getValue(PREFIX_SORT_BY).get().toLowerCase()); + } + +} diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index f4cf39d4c5a..738a6aa19f3 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -3,16 +3,20 @@ import static java.util.Objects.requireNonNull; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; import seedu.address.commons.util.ToStringBuilder; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.messages.ModuleMessages; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; import seedu.address.model.person.UniquePersonList; /** @@ -22,6 +26,7 @@ public class AddressBook implements ReadOnlyAddressBook { private final UniquePersonList persons; + private ObservableList sortedPersons; private final ArrayList modules; private final ArrayList tutorialClasses; @@ -99,6 +104,24 @@ public boolean hasPerson(Person person) { return persons.contains(person); } + /** + * Returns true if a person with the same identity as {@code person} exists in + * the address book. + */ + public boolean hasPersonWithStudentId(StudentId id) { + requireNonNull(id); + return persons.asUnmodifiableObservableList().stream().anyMatch(s -> s.getStudentId().equals(id)); + } + + /** + * Returns true if a person with the same identity as {@code person} exists in + * the address book. + */ + public boolean hasPersonWithEmail(Email email) { + requireNonNull(email); + return persons.asUnmodifiableObservableList().stream().anyMatch(s -> s.getEmail().equals(email)); + } + /** * Adds a person to the address book. * The person must not already exist in the address book. @@ -185,6 +208,26 @@ public void addPersonToTutorialClass(Person person, ModuleCode module, TutorialC tutorialClassInList.addStudent(person); } + /** + * Deletes a person from the students list of a specific tutorial class within a + * module. + */ + public void deletePersonFromTutorialClass(Person person, ModuleCode module, TutorialClass tutorialClass) { + requireNonNull(person); + requireNonNull(module); + requireNonNull(tutorialClass); + + ModuleCode moduleInList = findModuleFromList(module); + if (moduleInList == null) { + throw new IllegalArgumentException("Module does not exist in the address book."); + } + TutorialClass tutorialClassInList = moduleInList.getTutorialClasses().stream() + .filter(tutorial -> tutorial.equals(tutorialClass)) + .findFirst() + .orElse(null); + tutorialClassInList.deleteStudent(person); + } + /** * Replaces the given person {@code target} in the list with * {@code editedPerson}. @@ -199,13 +242,20 @@ public void setPerson(Person target, Person editedPerson) { } /** - * Removes {@code key} from this {@code AddressBook}. + * Removes Person {@code key} from this {@code AddressBook}. * {@code key} must exist in the address book. */ public void removePerson(Person key) { persons.remove(key); } + /** + * Removes ModuleCode {@code key} from this {@code AddressBook}. + * {@code key} must exist in the address book. + */ + public void removeModule(ModuleCode key) { + modules.remove(key); + } //// util methods @Override @@ -228,6 +278,15 @@ public ObservableList getModuleList() { public ObservableList getTutorialList() { return FXCollections.observableList(tutorialClasses); } + @Override + public void setSortedPersonList(Comparator comparator) { + sortedPersons = new FilteredList<>(persons.asUnmodifiableObservableList().sorted(comparator)); + } + @Override + public ObservableList getSortedPersonList() { + return sortedPersons; + } + @Override public boolean equals(Object other) { if (other == this) { diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index b3a65fbf354..4f85568fca7 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -1,6 +1,7 @@ package seedu.address.model; import java.nio.file.Path; +import java.util.Comparator; import java.util.function.Predicate; import javafx.collections.ObservableList; @@ -8,7 +9,9 @@ import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; /** * The API of the Model component. @@ -61,6 +64,17 @@ public interface Model { * Returns true if a person with the same identity as {@code person} exists in the address book. */ boolean hasPerson(Person person); + + /** + * Returns true if a person with the same email as {@code person} exists in the address book. + */ + boolean hasPersonWithEmail(Email email); + + /** + * Returns true if a person with the same student id as {@code person} exists in the address book. + */ + boolean hasPersonWithStudentId(StudentId id); + /** * Finds the module object from the list if it exists. Else, returns null. * @@ -82,6 +96,12 @@ public interface Model { */ void deletePerson(Person target); + /** + * Deletes the given module. + * The module must exist in the address book. + */ + void deleteModule(ModuleCode target); + /** * Adds the given person. * {@code person} must not already exist in the address book. @@ -109,6 +129,7 @@ public interface Model { /** Returns an unmodifiable view of the filtered person list */ ObservableList getFilteredPersonList(); ObservableList getFilteredModuleList(); + ObservableList getSortedPersonList(Comparator comparator); /** * Updates the filter of the filtered person list to filter by the given {@code predicate}. @@ -130,4 +151,8 @@ public interface Model { */ Person searchPersonByPredicate(Predicate predicate); + /** + * Deletes the given person from the given tutorial class in the given module. + */ + void deletePersonFromTutorialClass(Person personToAdd, ModuleCode module, TutorialClass tutorialClass); } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 89114f11e07..101d78b8d9b 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -4,6 +4,7 @@ import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; import java.nio.file.Path; +import java.util.Comparator; import java.util.function.Predicate; import java.util.logging.Logger; @@ -13,7 +14,9 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; /** @@ -98,6 +101,19 @@ public boolean hasPerson(Person person) { requireNonNull(person); return addressBook.hasPerson(person); } + + @Override + public boolean hasPersonWithStudentId(StudentId id) { + requireAllNonNull(id); + return addressBook.hasPersonWithStudentId(id); + } + + @Override + public boolean hasPersonWithEmail(Email email) { + requireAllNonNull(email); + return addressBook.hasPersonWithEmail(email); + } + @Override public ModuleCode findModuleFromList(ModuleCode module) { requireNonNull(module); @@ -118,6 +134,11 @@ public void deletePerson(Person target) { addressBook.removePerson(target); } + @Override + public void deleteModule(ModuleCode target) { + addressBook.removeModule(target); + } + @Override public void addPerson(Person person) { addressBook.addPerson(person); @@ -135,6 +156,11 @@ public void addPersonToTutorialClass(Person person, ModuleCode module, TutorialC addressBook.addPersonToTutorialClass(person, module, tutorialClass); } + @Override + public void deletePersonFromTutorialClass(Person person, ModuleCode module, TutorialClass tutorialClass) { + addressBook.deletePersonFromTutorialClass(person, module, tutorialClass); + } + @Override public void setPerson(Person target, Person editedPerson) { requireAllNonNull(target, editedPerson); @@ -161,6 +187,12 @@ public ObservableList getFilteredModuleList() { return filteredModules; } + @Override + public ObservableList getSortedPersonList(Comparator comparator) { + addressBook.setSortedPersonList(comparator); + return addressBook.getSortedPersonList(); + } + @Override public void updateFilteredPersonList(Predicate predicate) { requireNonNull(predicate); diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java index 396ef7c652f..840d98b1e28 100644 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java @@ -1,5 +1,7 @@ package seedu.address.model; +import java.util.Comparator; + import javafx.collections.ObservableList; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; @@ -22,6 +24,9 @@ public interface ReadOnlyAddressBook { */ ObservableList getModuleList(); + void setSortedPersonList(Comparator comparator); + ObservableList getSortedPersonList(); + /** * Checks if the address book contains the specified module code. * diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 9c8a5ce5407..b718c87af0a 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -19,6 +19,7 @@ import seedu.address.logic.commands.CommandResult; import seedu.address.logic.commands.DeleteClassCommand; import seedu.address.logic.commands.ListClassesCommand; +import seedu.address.logic.commands.SortStudentCommand; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.module.ModuleCode; @@ -182,6 +183,11 @@ void switchToModuleListPanel() { } + private void switchToSortedPersonListPanel() { + personListPanel = new PersonListPanel(logic.getAddressBook().getSortedPersonList()); + personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + } + /** * Sets the default size based on {@code guiSettings}. */ @@ -237,6 +243,15 @@ public static boolean useModuleView(String commandText) { || commandWord.equals(AddClassCommand.COMMAND_WORD) || commandWord.equals(DeleteClassCommand.COMMAND_WORD); } + + /** + * Returns true if the command requires sorted view. + */ + public static boolean useSortedView(String commandText) { + String commandWord = commandText.split(" ")[0]; + return commandWord.equals(SortStudentCommand.COMMAND_WORD); + } + public PersonListPanel getPersonListPanel() { return personListPanel; } @@ -264,6 +279,8 @@ private CommandResult executeCommand(String commandText) throws CommandException if (useModuleView(commandText)) { switchToModuleListPanel(); + } else if (useSortedView(commandText)) { + switchToSortedPersonListPanel(); } else { switchToPersonListPanel(); } diff --git a/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java b/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java index 166a3098900..e448a9e9e1e 100644 --- a/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddStudentCommandTest.java @@ -10,6 +10,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.function.Predicate; import org.junit.jupiter.api.Test; @@ -24,7 +25,9 @@ import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; import seedu.address.testutil.PersonBuilder; /** @@ -145,6 +148,16 @@ public boolean hasPerson(Person person) { throw new AssertionError("This method should not be called."); } + @Override + public boolean hasPersonWithEmail(Email email) { + throw new AssertionError("This method should not be called."); + } + + @Override + public boolean hasPersonWithStudentId(StudentId studentId) { + throw new AssertionError("This method should not be called."); + } + @Override public TutorialClass findTutorialClassFromList(TutorialClass tutorialClass, ModuleCode moduleCode) { throw new AssertionError("This method should not be called."); @@ -155,11 +168,21 @@ public void addPersonToTutorialClass(Person person, ModuleCode moduleCode, Tutor throw new AssertionError("This method should not be called."); } + @Override + public void deletePersonFromTutorialClass(Person person, ModuleCode moduleCode, TutorialClass tutorialClass) { + throw new AssertionError("This method should not be called."); + } + @Override public void deletePerson(Person target) { throw new AssertionError("This method should not be called."); } + @Override + public void deleteModule(ModuleCode target) { + throw new AssertionError("This method should not be called."); + } + @Override public void addModule(ModuleCode module) { throw new AssertionError("This method should not be called."); @@ -184,6 +207,11 @@ public ObservableList getFilteredModuleList() { throw new AssertionError("This method should not be called."); } + @Override + public ObservableList getSortedPersonList(Comparator comparator) { + throw new AssertionError("This method should not be called."); + } + @Override public void updateFilteredPersonList(Predicate predicate) { throw new AssertionError("This method should not be called."); diff --git a/src/test/java/seedu/address/logic/commands/DeleteModuleCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteModuleCommandTest.java new file mode 100644 index 00000000000..afb926634f2 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteModuleCommandTest.java @@ -0,0 +1,74 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_BOB; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.messages.ModuleMessages.MESSAGE_DELETE_MODULE_SUCCESS; +import static seedu.address.logic.messages.ModuleMessages.MESSAGE_MODULE_NOT_FOUND; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.module.ModuleCode; + +/** + * Contains integration tests (interaction with the Model) for + * {@code DeleteModuleCommand}. + */ +public class DeleteModuleCommandTest { + private final Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_success() { + Model actualModel = new ModelManager(); + Model expectedModel = new ModelManager(); + ModuleCode module = new ModuleCode(VALID_MODULE_AMY); + actualModel.addModule(module); + + assertCommandSuccess(new DeleteModuleCommand(new ModuleCode(VALID_MODULE_AMY)), actualModel, + String.format(MESSAGE_DELETE_MODULE_SUCCESS, VALID_MODULE_AMY), expectedModel); + + assertEquals(actualModel.getFilteredModuleList().size(), 0); + } + + @Test + public void execute_moduleNotFound_fail() { + ModuleCode module = new ModuleCode(VALID_MODULE_AMY); + model.addModule(module); + + assertCommandFailure(new DeleteModuleCommand(new ModuleCode(VALID_MODULE_BOB)), model, + String.format(MESSAGE_MODULE_NOT_FOUND, VALID_MODULE_BOB)); + } + + @Test + public void equals() { + final DeleteModuleCommand standardCommand = new DeleteModuleCommand(new ModuleCode(VALID_MODULE_AMY)); + + // same values -> returns true + DeleteModuleCommand commandWithSameValues = new DeleteModuleCommand(new ModuleCode(VALID_MODULE_AMY)); + 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 module code -> returns false + assertFalse(standardCommand.equals(new DeleteModuleCommand(new ModuleCode(VALID_MODULE_BOB)))); + + // different tutorial class -> returns true + assertTrue(standardCommand.equals(new DeleteModuleCommand(new ModuleCode(VALID_MODULE_AMY)))); + } +} + diff --git a/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandIntegrationTest.java new file mode 100644 index 00000000000..f7f60ea2caf --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandIntegrationTest.java @@ -0,0 +1,118 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_BOB; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.logic.Messages; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByEmailCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIdCommand; +import seedu.address.logic.messages.ModuleMessages; +import seedu.address.logic.messages.PersonMessages; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Person; +import seedu.address.testutil.PersonBuilder; + +/** + * Contains integration tests (interaction with the Model) for + * {@code DeleteStudentFromClassCommand}. + */ +public class DeleteStudentFromClassCommandIntegrationTest { + + private Model model; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + ModuleCode newModule = new ModuleCode(VALID_MODULE_AMY); + model.addModule(newModule); + TutorialClass newTutorialClass = new TutorialClass(VALID_TUTORIAL_AMY); + newModule.addTutorialClass(newTutorialClass); + Person validPerson = new PersonBuilder().build(); + Person validPerson2 = new PersonBuilder().withName("otherName").withEmail("other@example.com") + .withStudentId("A0000000A").build(); + model.addPerson(validPerson); + newModule.getTutorialClasses().get(0).addStudent(validPerson); + newModule.getTutorialClasses().get(0).addStudent(validPerson2); + } + + @Test + public void execute_deleteStudentFromClassById_success() { + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + + ModuleCode newModule = new ModuleCode(VALID_MODULE_AMY); + expectedModel.addModule(newModule); + Person validPerson2 = new PersonBuilder().withName("otherName").withEmail("other@example.com") + .withStudentId("A0000000A").build(); + TutorialClass newTutorialClass = new TutorialClass(VALID_TUTORIAL_AMY); + newModule.addTutorialClass(newTutorialClass); + newModule.getTutorialClasses().get(0).addStudent(validPerson2); + Person validPerson = new PersonBuilder().build(); + + // Attempt to delete the student + assertCommandSuccess(new DeleteStudentFromClassByIdCommand(validPerson.getStudentId(), + newModule, newTutorialClass), + model, + String.format(PersonMessages.MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS, Messages.format(validPerson), + newModule, newTutorialClass), + expectedModel); + } + + @Test + public void execute_deleteStudentFromClassByEmail_success() { + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + + ModuleCode newModule = new ModuleCode(VALID_MODULE_AMY); + expectedModel.addModule(newModule); + Person validPerson2 = new PersonBuilder().withName("otherName").withEmail("other@example.com") + .withStudentId("A0000000A").build(); + TutorialClass newTutorialClass = new TutorialClass(VALID_TUTORIAL_AMY); + newModule.addTutorialClass(newTutorialClass); + newModule.getTutorialClasses().get(0).addStudent(validPerson2); + Person validPerson = new PersonBuilder().build(); + + // Attempt to delete the student + assertCommandSuccess(new DeleteStudentFromClassByEmailCommand(validPerson.getEmail(), + newModule, newTutorialClass), + model, + String.format(PersonMessages.MESSAGE_DELETE_STUDENT_FROM_CLASS_SUCCESS, Messages.format(validPerson), + newModule, newTutorialClass), expectedModel); + } + + @Test + public void execute_deleteStudentFromInvalidClass_throwsCommandException() { + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + + ModuleCode newModule = new ModuleCode(VALID_MODULE_BOB); + TutorialClass newTutorial = new TutorialClass(VALID_TUTORIAL_BOB); + Person validPerson = new PersonBuilder().build(); + + assertCommandFailure(new DeleteStudentFromClassByEmailCommand(validPerson.getEmail(), newModule, newTutorial), + expectedModel, String.format(ModuleMessages.MESSAGE_MODULE_NOT_FOUND, newModule)); + } + + @Test + public void execute_deleteStudentFromValidModuleButInvalidTutorial_throwsCommandException() { + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + + ModuleCode newModule = new ModuleCode(VALID_MODULE_AMY); + expectedModel.addModule(newModule); + TutorialClass newTutorial = new TutorialClass(VALID_TUTORIAL_BOB); + Person validPerson = new PersonBuilder().build(); + assertCommandFailure(new DeleteStudentFromClassByEmailCommand(validPerson.getEmail(), newModule, newTutorial), + expectedModel, + String.format(ModuleMessages.MESSAGE_TUTORIAL_DOES_NOT_BELONG_TO_MODULE, newTutorial, newModule)); + } + +} diff --git a/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandTest.java new file mode 100644 index 00000000000..4cc5887dbed --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteStudentFromClassCommandTest.java @@ -0,0 +1,167 @@ +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.INVALID_PERSON_EMAIL; +import static seedu.address.logic.commands.CommandTestUtil.INVALID_PERSON_STUDENT_ID; +import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_STUDENT_ID_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_STUDENT_ID_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_BOB; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +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.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByEmailCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIdCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIndexCommand; +import seedu.address.logic.messages.PersonMessages; +import seedu.address.logic.messages.TutorialClassMessages; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.TutorialClass; +import seedu.address.model.person.Email; +import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; +import seedu.address.testutil.PersonBuilder; + +/** + * Contains integration tests (interaction with the Model) and unit tests for + * {@code DeleteStudentFromClassCommand}. + */ +public class DeleteStudentFromClassCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + private TutorialClass tutorialClass; + + @BeforeEach + public void setUp() { + ModuleCode newModule = new ModuleCode(VALID_MODULE_AMY); + model.addModule(newModule); + TutorialClass newTutorialClass = new TutorialClass(VALID_TUTORIAL_AMY); + newModule.addTutorialClass(newTutorialClass); + tutorialClass = newTutorialClass; + } + + @Test + public void execute_invalidStudent_fail() { + DeleteStudentFromClassByEmailCommand deleteStudentFromClassByEmailCommand = + new DeleteStudentFromClassByEmailCommand(new Email(INVALID_PERSON_EMAIL), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByIdCommand deleteStudentFromClassByIdCommand = + new DeleteStudentFromClassByIdCommand(new StudentId(INVALID_PERSON_STUDENT_ID), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByIndexCommand deleteStudentFromClassByIndexCommand = + new DeleteStudentFromClassByIndexCommand(Index.fromOneBased(1000), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + assertCommandFailure(deleteStudentFromClassByEmailCommand, model, + String.format(PersonMessages.MESSAGE_PERSON_EMAIL_NOT_FOUND, INVALID_PERSON_EMAIL)); + + assertCommandFailure(deleteStudentFromClassByIdCommand, model, + String.format(PersonMessages.MESSAGE_PERSON_STUDENT_ID_NOT_FOUND, INVALID_PERSON_STUDENT_ID)); + + assertCommandFailure(deleteStudentFromClassByIndexCommand, model, + String.format(PersonMessages.MESSAGE_PERSON_INDEX_NOT_FOUND, 1000)); + } + + @Test + public void execute_studentDoesNotExist_fail() { + Person person = new PersonBuilder().build(); + Person otherPerson = new PersonBuilder().withName("otherPerson").build(); + model.addPerson(person); + tutorialClass.addStudent(otherPerson); + + DeleteStudentFromClassByEmailCommand addStudentToClassByEmailCommand = + new DeleteStudentFromClassByEmailCommand(person.getEmail(), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByIdCommand addStudentToClassByIdCommand = + new DeleteStudentFromClassByIdCommand(person.getStudentId(), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + assertCommandFailure(addStudentToClassByIdCommand, model, + String.format(TutorialClassMessages.MESSAGE_STUDENT_NOT_FOUND_IN_CLASS, Messages.format(person), + tutorialClass)); + + assertCommandFailure(addStudentToClassByEmailCommand, model, + String.format(TutorialClassMessages.MESSAGE_STUDENT_NOT_FOUND_IN_CLASS, Messages.format(person), + tutorialClass)); + } + + @Test + public void equals() { + + // Test index based delete command + DeleteStudentFromClassByIndexCommand deleteStudentFromClassByIndexFirstCommand = + new DeleteStudentFromClassByIndexCommand(INDEX_FIRST_PERSON, + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByIndexCommand deleteStudentFromClassByIndexSecondCommand = + new DeleteStudentFromClassByIndexCommand(INDEX_SECOND_PERSON, + new ModuleCode(VALID_MODULE_BOB), new TutorialClass(VALID_TUTORIAL_BOB)); + + // same object -> returns true + assertTrue(deleteStudentFromClassByIndexFirstCommand.equals(deleteStudentFromClassByIndexFirstCommand)); + // different types -> returns false + assertFalse(deleteStudentFromClassByIndexFirstCommand.equals(1)); + + // null -> returns false + assertFalse(deleteStudentFromClassByIndexFirstCommand.equals(null)); + + // different person -> returns false + assertFalse(deleteStudentFromClassByIndexFirstCommand.equals(deleteStudentFromClassByIndexSecondCommand)); + + // Test email based delete command + DeleteStudentFromClassByEmailCommand deleteStudentFromClassByEmailFirstCommand = + new DeleteStudentFromClassByEmailCommand(new Email(VALID_EMAIL_AMY), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByEmailCommand deleteStudentFromClassByEmailSecondCommand = + new DeleteStudentFromClassByEmailCommand(new Email(VALID_EMAIL_BOB), + new ModuleCode(VALID_MODULE_BOB), new TutorialClass(VALID_TUTORIAL_BOB)); + + // same object -> returns true + assertTrue(deleteStudentFromClassByEmailFirstCommand.equals(deleteStudentFromClassByEmailFirstCommand)); + // different types -> returns false + assertFalse(deleteStudentFromClassByEmailFirstCommand.equals(1)); + + // null -> returns false + assertFalse(deleteStudentFromClassByEmailFirstCommand.equals(null)); + + // different person -> returns false + assertFalse(deleteStudentFromClassByEmailFirstCommand.equals(deleteStudentFromClassByEmailSecondCommand)); + + // Test student id based delete command + DeleteStudentFromClassByIdCommand deleteStudentFromClassByIdFirstCommand = + new DeleteStudentFromClassByIdCommand(new StudentId(VALID_STUDENT_ID_AMY), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + + DeleteStudentFromClassByIdCommand deleteStudentFromClassByIdSecondCommand = + new DeleteStudentFromClassByIdCommand(new StudentId(VALID_STUDENT_ID_BOB), + new ModuleCode(VALID_MODULE_BOB), new TutorialClass(VALID_TUTORIAL_BOB)); + + // same object -> returns true + assertTrue(deleteStudentFromClassByIdFirstCommand.equals(deleteStudentFromClassByIdFirstCommand)); + // different types -> returns false + assertFalse(deleteStudentFromClassByIdFirstCommand.equals(1)); + // null -> returns false + assertFalse(deleteStudentFromClassByIdFirstCommand.equals(null)); + // different person -> returns false + assertFalse(deleteStudentFromClassByIdFirstCommand.equals(deleteStudentFromClassByIdSecondCommand)); + } +} diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java index 32d9c395483..1b097e7c692 100644 --- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java @@ -23,7 +23,9 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.person.Email; import seedu.address.model.person.Person; +import seedu.address.model.person.StudentId; import seedu.address.testutil.EditPersonDescriptorBuilder; import seedu.address.testutil.PersonBuilder; @@ -104,6 +106,20 @@ public void execute_duplicatePersonUnfilteredList_failure() { EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); + + // duplicate email + descriptor = new EditPersonDescriptorBuilder().withName("Test").withEmail(firstPerson.getEmail().toString()) + .withStudentId("A1111111A").build(); + editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); + + // duplicate student id + descriptor = new EditPersonDescriptorBuilder().withName("Test").withEmail("test@example.com") + .withStudentId(firstPerson.getStudentId().toString()).build(); + editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); } @Test @@ -116,6 +132,20 @@ public void execute_duplicatePersonFilteredList_failure() { new EditPersonDescriptorBuilder(personInList).build()); assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); + + // edit person with only duplicate email + EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName("Test") + .withEmail(personInList.getEmail().toString()).withStudentId("A1111111A").build(); + editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); + + // edit person with only duplicate id + descriptor = new EditPersonDescriptorBuilder().withName("Test").withEmail("test@example.com") + .withStudentId(personInList.getStudentId().toString()).build(); + editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON); } @Test @@ -127,6 +157,70 @@ public void execute_invalidPersonIndexUnfilteredList_failure() { assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); } + @Test + public void execute_duplicateEmailUnfilteredList_failure() { + // edit with duplicate email + Email secondPersonEmail = model.getFilteredPersonList().get(INDEX_SECOND_PERSON.getZeroBased()).getEmail(); + + EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder() + .withEmail(secondPersonEmail.toString()).build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_EMAIL); + + // edit with own email + Email firstPersonEmail = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()).getEmail(); + descriptor = new EditPersonDescriptorBuilder().withEmail(firstPersonEmail.toString()).build(); + editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_EMAIL); + } + + @Test + public void execute_duplicateEmailFilteredList_failure() { + showPersonAtIndex(model, INDEX_FIRST_PERSON); + + Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased()); + EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder() + .withEmail(personInList.getEmail().toString()).build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_EMAIL); + } + + @Test + public void execute_duplicateStudentIdUnfilteredList_failure() { + // edit with duplicate student id + StudentId secondPersonStudentId = model.getFilteredPersonList() + .get(INDEX_SECOND_PERSON.getZeroBased()).getStudentId(); + + EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder() + .withStudentId(secondPersonStudentId.toString()).build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_STUDENTID); + + // edit with own student id + StudentId firstPersonStudentId = model.getFilteredPersonList() + .get(INDEX_FIRST_PERSON.getZeroBased()).getStudentId(); + descriptor = new EditPersonDescriptorBuilder().withStudentId(firstPersonStudentId.toString()).build(); + editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_STUDENTID); + } + + @Test + public void execute_duplicateStudentIdFilteredList_failure() { + showPersonAtIndex(model, INDEX_FIRST_PERSON); + + Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased()); + EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder() + .withStudentId(personInList.getStudentId().toString()).build(); + EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); + + assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_STUDENTID); + } + /** * Edit filtered list where index is larger than size of filtered list, * but smaller than size of address book diff --git a/src/test/java/seedu/address/logic/commands/SortStudentCommandTest.java b/src/test/java/seedu/address/logic/commands/SortStudentCommandTest.java new file mode 100644 index 00000000000..01e4ae9ecaf --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/SortStudentCommandTest.java @@ -0,0 +1,100 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortStudentCommand.MESSAGE_INVALID_PARAMETER; +import static seedu.address.logic.commands.SortStudentCommand.MESSAGE_SORT_STUDENT_SUCCESS; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import java.util.Comparator; + +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.Person; + +/** + * Contains integration tests (interaction with the Model) for {@code SortStudentCommand}. + */ +public class SortStudentCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void equals() { + SortStudentCommand firstCommand = new SortStudentCommand("name"); + SortStudentCommand secondCommand = new SortStudentCommand("id"); + + // same object -> returns true + assertTrue(firstCommand.equals(firstCommand)); + + // same values -> returns true + SortStudentCommand sortFirstCommandCopy = new SortStudentCommand("name"); + assertTrue(firstCommand.equals(sortFirstCommandCopy)); + + // different types -> returns false + assertFalse(firstCommand.equals(1)); + + // null -> returns false + assertFalse(firstCommand.equals(null)); + + // different sortBy -> returns false + assertFalse(firstCommand.equals(secondCommand)); + } + + @Test + public void execute_validParameter_success() { + String expectedMessage = MESSAGE_SORT_STUDENT_SUCCESS; + + // sort by name + Comparator comparator = Comparator.comparing(p -> p.getName().toString()); + SortStudentCommand command = new SortStudentCommand("name"); + + expectedModel.getSortedPersonList(comparator); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + + // sort by id + comparator = Comparator.comparing(p -> p.getStudentId().toString()); + command = new SortStudentCommand("id"); + + expectedModel.getSortedPersonList(comparator); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + + // sort by email + comparator = Comparator.comparing(p -> p.getEmail().toString()); + command = new SortStudentCommand("id"); + + expectedModel.getSortedPersonList(comparator); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidParameters_failure() { + // empty parameter + SortStudentCommand command = new SortStudentCommand(""); + assertCommandFailure(command, model, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + + // invalid parameter + command = new SortStudentCommand("test"); + assertCommandFailure(command, model, MESSAGE_INVALID_PARAMETER); + + // case-sensitive + command = new SortStudentCommand("NAME"); + assertCommandFailure(command, model, MESSAGE_INVALID_PARAMETER); + } + + @Test + public void toStringMethod() { + SortStudentCommand command = new SortStudentCommand("name"); + String expected = SortStudentCommand.class.getCanonicalName() + "{sortBy=name}"; + assertEquals(expected, command.toString()); + } +} diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 4ac522093bb..d9e78c2f834 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.address.logic.commands.CommandTestUtil.INDEX_ONE; import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; import static seedu.address.logic.commands.CommandTestUtil.VALID_STUDENT_ID_AMY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; @@ -25,6 +26,7 @@ import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.DeleteClassCommand; import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.DeleteModuleCommand; import seedu.address.logic.commands.DeleteTeamCommand; import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; @@ -39,6 +41,9 @@ import seedu.address.logic.commands.addstudenttoclasscommands.AddStudentToClassCommand; import seedu.address.logic.commands.deletestudentcommands.DeleteStudentByIdCommand; import seedu.address.logic.commands.deletestudentcommands.DeleteStudentCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByEmailCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIdCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassCommand; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.module.ModuleCode; import seedu.address.model.module.TutorialClass; @@ -82,7 +87,7 @@ public void parseCommand_edit() throws Exception { Person person = new PersonBuilder().build(); EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build(); EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " " - + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor)); + + INDEX_ONE + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor)); assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command); } @@ -133,6 +138,16 @@ public void parseCommand_deleteClass() throws Exception { new TutorialClass(tutorialClass)), command); } + @Test + public void parseCommand_deleteModule() throws Exception { + final String moduleCode = "CS2103T"; + DeleteModuleCommand command = (DeleteModuleCommand) parser.parseCommand(DeleteModuleCommand.COMMAND_WORD + " " + + PREFIX_MODULECODE + moduleCode); + assertEquals(new DeleteModuleCommand(new ModuleCode(moduleCode)), command); + } + + + @Test public void parseCommand_listClasses() throws Exception { assertTrue(parser.parseCommand(ListClassesCommand.COMMAND_WORD) instanceof ListClassesCommand); @@ -161,6 +176,29 @@ public void parseCommand_addStudentToClass() throws Exception { } + @Test + public void parseCommand_deleteStudentFromClass() throws Exception { + final String moduleCode = "CS2103T"; + final String tutorialClass = "T09"; + final String email = VALID_EMAIL_AMY; + final String id = VALID_STUDENT_ID_AMY; + final Index index = INDEX_FIRST_PERSON; + DeleteStudentFromClassCommand deleteByEmailCommand = (DeleteStudentFromClassCommand) parser.parseCommand( + DeleteStudentFromClassCommand.COMMAND_WORD + " " + + PREFIX_EMAIL + email + " " + PREFIX_MODULECODE + + moduleCode + " " + PREFIX_TUTORIALCLASS + tutorialClass); + + DeleteStudentFromClassCommand deleteByIdCommand = (DeleteStudentFromClassCommand) parser.parseCommand( + DeleteStudentFromClassCommand.COMMAND_WORD + " " + + PREFIX_STUDENTID + id + " " + PREFIX_MODULECODE + + moduleCode + " " + PREFIX_TUTORIALCLASS + tutorialClass); + + assertEquals(new DeleteStudentFromClassByEmailCommand(new Email(VALID_EMAIL_AMY), + new ModuleCode(moduleCode), new TutorialClass(tutorialClass)), deleteByEmailCommand); + + assertEquals(new DeleteStudentFromClassByIdCommand(new StudentId(VALID_STUDENT_ID_AMY), + new ModuleCode(moduleCode), new TutorialClass(tutorialClass)), deleteByIdCommand); + } @Test public void parseCommand_unrecognisedInput_throwsParseException() { assertThrows(ParseException.class, diff --git a/src/test/java/seedu/address/logic/parser/DeleteModuleCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteModuleCommandParserTest.java new file mode 100644 index 00000000000..331c5d3ff83 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/DeleteModuleCommandParserTest.java @@ -0,0 +1,46 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.commands.CommandTestUtil.MODULE_DESC_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_AMY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULECODE; +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.logic.Messages; +import seedu.address.logic.commands.DeleteModuleCommand; +import seedu.address.model.module.ModuleCode; + +/** + * As we are only doing white-box testing, our test cases do not cover path variations + * outside of the DeleteModuleCommand code. For example, inputs "1" and "1 abc" take the + * same path through the DeleteModuleCommand, and therefore we test only one of them. + * The path variation for those two cases occur inside the ParserUtil, and + * therefore should be covered by the ParserUtilTest. + */ +public class DeleteModuleCommandParserTest { + private final DeleteModuleCommandParser parser = new DeleteModuleCommandParser(); + + + @Test + public void parse_validModule_success() { + String userInput = MODULE_DESC_AMY; + DeleteModuleCommand expectedCommand = new DeleteModuleCommand(new ModuleCode(VALID_MODULE_AMY)); + assertParseSuccess(parser, userInput, expectedCommand); + } + + @Test + public void parse_missingCompulsoryField_failure() { + String expectedMessage1 = String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, + DeleteModuleCommand.MESSAGE_USAGE); + String expectedMessage2 = ModuleCode.MESSAGE_CONSTRAINTS; + + // no parameters + assertParseFailure(parser, " ", expectedMessage1); + + // invalid module stated + assertParseFailure(parser, " " + PREFIX_MODULECODE + "INVALID", expectedMessage2); + } +} + diff --git a/src/test/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParserTest.java new file mode 100644 index 00000000000..06258ac9c19 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/DeleteStudentFromClassCommandParserTest.java @@ -0,0 +1,50 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static seedu.address.logic.commands.CommandTestUtil.MODULE_DESC_AMY; +import static seedu.address.logic.commands.CommandTestUtil.STUDENT_ID_DESC_BOB; +import static seedu.address.logic.commands.CommandTestUtil.TUTORIAL_DESC_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_MODULE_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TUTORIAL_AMY; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; +import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; +import static seedu.address.testutil.TypicalPersons.BOB; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByEmailCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassByIdCommand; +import seedu.address.logic.commands.deletestudentfromclasscommands.DeleteStudentFromClassCommand; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.TutorialClass; + +public class DeleteStudentFromClassCommandParserTest { + + private DeleteStudentFromClassCommandParser parser = new DeleteStudentFromClassCommandParser(); + @Test + public void parse_validArgs_returnsDeleteStudentFromClassCommand() { + + String commandSuffix = MODULE_DESC_AMY + TUTORIAL_DESC_AMY; + + // Delete by email + DeleteStudentFromClassByEmailCommand expectedDeleteByEmailCommand = + new DeleteStudentFromClassByEmailCommand(BOB.getEmail(), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + assertParseSuccess(parser, EMAIL_DESC_BOB + commandSuffix, expectedDeleteByEmailCommand); + + // Delete by student Id + DeleteStudentFromClassByIdCommand expectedDeleteByIdCommand = + new DeleteStudentFromClassByIdCommand(BOB.getStudentId(), + new ModuleCode(VALID_MODULE_AMY), new TutorialClass(VALID_TUTORIAL_AMY)); + assertParseSuccess(parser, STUDENT_ID_DESC_BOB + commandSuffix, expectedDeleteByIdCommand); + + } + + @Test + public void parse_invalidArgs_throwsParseException() { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, + DeleteStudentFromClassCommand.MESSAGE_USAGE); + assertParseFailure(parser, "a", expectedMessage); + } +} diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java index b047913bd69..6cc3f60984f 100644 --- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java @@ -3,6 +3,8 @@ import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY; import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB; +import static seedu.address.logic.commands.CommandTestUtil.INDEX_ONE; +import static seedu.address.logic.commands.CommandTestUtil.INDEX_TWO; import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC; import static seedu.address.logic.commands.CommandTestUtil.INVALID_STUDENT_ID_DESC; @@ -19,13 +21,13 @@ import static seedu.address.logic.commands.CommandTestUtil.VALID_STUDENT_ID_BOB; import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INDEX; import static seedu.address.logic.parser.CliSyntax.PREFIX_STUDENTID; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure; import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; -import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON; import org.junit.jupiter.api.Test; @@ -54,10 +56,10 @@ public class EditCommandParserTest { @Test public void parse_missingParts_failure() { // no index specified - assertParseFailure(parser, VALID_NAME_AMY, MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); // no field specified - assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED); + assertParseFailure(parser, INDEX_TWO, EditCommand.MESSAGE_NOT_EDITED); // no index and no field specified assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT); @@ -66,60 +68,58 @@ public void parse_missingParts_failure() { @Test public void parse_invalidPreamble_failure() { // negative index - assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, " " + PREFIX_INDEX + "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); // zero index - assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, " " + PREFIX_INDEX + "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT); // invalid arguments being parsed as preamble - assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, " " + PREFIX_INDEX + "1 some random string", MESSAGE_INVALID_FORMAT); // invalid prefix being parsed as preamble - assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT); + assertParseFailure(parser, " " + PREFIX_INDEX + "1 i/ string", MESSAGE_INVALID_FORMAT); } @Test public void parse_invalidValue_failure() { - assertParseFailure(parser, "1" + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name - assertParseFailure(parser, "1" + INVALID_STUDENT_ID_DESC, StudentId.MESSAGE_CONSTRAINTS); // invalid studentid - assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email - assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag + assertParseFailure(parser, INDEX_ONE + INVALID_NAME_DESC, Name.MESSAGE_CONSTRAINTS); // invalid name + assertParseFailure(parser, INDEX_ONE + INVALID_STUDENT_ID_DESC, StudentId.MESSAGE_CONSTRAINTS); // invalid id + assertParseFailure(parser, INDEX_ONE + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email + assertParseFailure(parser, INDEX_ONE + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag // invalid student id followed by valid email - assertParseFailure(parser, "1" + INVALID_STUDENT_ID_DESC + EMAIL_DESC_AMY, StudentId.MESSAGE_CONSTRAINTS); + assertParseFailure(parser, INDEX_ONE + INVALID_STUDENT_ID_DESC + EMAIL_DESC_AMY, StudentId.MESSAGE_CONSTRAINTS); // while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited, // parsing it together with a valid tag results in error - assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS); - assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); - assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); + assertParseFailure(parser, INDEX_ONE + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS); + assertParseFailure(parser, INDEX_ONE + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); + assertParseFailure(parser, INDEX_ONE + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS); // multiple invalid values, but only the first invalid value is captured - assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + assertParseFailure(parser, INDEX_ONE + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_MODULE_AMY + VALID_STUDENT_ID_AMY, Name.MESSAGE_CONSTRAINTS); } @Test public void parse_allFieldsSpecified_success() { - Index targetIndex = INDEX_SECOND_PERSON; - String userInput = targetIndex.getOneBased() + NAME_DESC_AMY + EMAIL_DESC_AMY + String userInput = INDEX_TWO + NAME_DESC_AMY + EMAIL_DESC_AMY + STUDENT_ID_DESC_AMY + TAG_DESC_FRIEND; EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY) .withEmail(VALID_EMAIL_AMY).withStudentId(VALID_STUDENT_ID_AMY).withTags(VALID_TAG_FRIEND).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + EditCommand expectedCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor); assertParseSuccess(parser, userInput, expectedCommand); } @Test public void parse_someFieldsSpecified_success() { - Index targetIndex = INDEX_FIRST_PERSON; - String userInput = targetIndex.getOneBased() + STUDENT_ID_DESC_BOB + EMAIL_DESC_AMY; + String userInput = INDEX_ONE + STUDENT_ID_DESC_BOB + EMAIL_DESC_AMY; EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withStudentId(VALID_STUDENT_ID_BOB) .withEmail(VALID_EMAIL_AMY).build(); - EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); + EditCommand expectedCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor); assertParseSuccess(parser, userInput, expectedCommand); } @@ -127,26 +127,26 @@ public void parse_someFieldsSpecified_success() { @Test public void parse_oneFieldSpecified_success() { // name - Index targetIndex = INDEX_THIRD_PERSON; - String userInput = targetIndex.getOneBased() + NAME_DESC_AMY; + Index targetIndex = INDEX_SECOND_PERSON; + String userInput = INDEX_TWO + NAME_DESC_AMY; EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).build(); EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); assertParseSuccess(parser, userInput, expectedCommand); // student id - userInput = targetIndex.getOneBased() + STUDENT_ID_DESC_AMY; + userInput = INDEX_TWO + STUDENT_ID_DESC_AMY; descriptor = new EditPersonDescriptorBuilder().withStudentId(VALID_STUDENT_ID_AMY).build(); expectedCommand = new EditCommand(targetIndex, descriptor); assertParseSuccess(parser, userInput, expectedCommand); // email - userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY; + userInput = INDEX_TWO + EMAIL_DESC_AMY; descriptor = new EditPersonDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build(); expectedCommand = new EditCommand(targetIndex, descriptor); assertParseSuccess(parser, userInput, expectedCommand); // tags - userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND; + userInput = INDEX_TWO + TAG_DESC_FRIEND; descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build(); expectedCommand = new EditCommand(targetIndex, descriptor); assertParseSuccess(parser, userInput, expectedCommand); @@ -159,17 +159,17 @@ public void parse_multipleRepeatedFields_failure() { // valid followed by invalid Index targetIndex = INDEX_FIRST_PERSON; - String userInput = targetIndex.getOneBased() + INVALID_STUDENT_ID_DESC + STUDENT_ID_DESC_BOB; + String userInput = INDEX_ONE + INVALID_STUDENT_ID_DESC + STUDENT_ID_DESC_BOB; assertParseFailure(parser, userInput, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_STUDENTID)); // invalid followed by valid - userInput = targetIndex.getOneBased() + STUDENT_ID_DESC_BOB + INVALID_STUDENT_ID_DESC; + userInput = INDEX_ONE + STUDENT_ID_DESC_BOB + INVALID_STUDENT_ID_DESC; assertParseFailure(parser, userInput, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_STUDENTID)); // mulltiple valid fields repeated - userInput = targetIndex.getOneBased() + STUDENT_ID_DESC_AMY + EMAIL_DESC_AMY + userInput = INDEX_ONE + STUDENT_ID_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND + STUDENT_ID_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND + STUDENT_ID_DESC_BOB + EMAIL_DESC_BOB; @@ -177,7 +177,7 @@ public void parse_multipleRepeatedFields_failure() { Messages.getErrorMessageForDuplicatePrefixes(PREFIX_STUDENTID, PREFIX_EMAIL)); // multiple invalid values - userInput = targetIndex.getOneBased() + INVALID_STUDENT_ID_DESC + INVALID_EMAIL_DESC + userInput = INDEX_ONE + INVALID_STUDENT_ID_DESC + INVALID_EMAIL_DESC + INVALID_STUDENT_ID_DESC + INVALID_EMAIL_DESC; assertParseFailure(parser, userInput, @@ -186,8 +186,8 @@ public void parse_multipleRepeatedFields_failure() { @Test public void parse_resetTags_success() { - Index targetIndex = INDEX_THIRD_PERSON; - String userInput = targetIndex.getOneBased() + TAG_EMPTY; + Index targetIndex = INDEX_SECOND_PERSON; + String userInput = INDEX_TWO + TAG_EMPTY; EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build(); EditCommand expectedCommand = new EditCommand(targetIndex, descriptor); diff --git a/src/test/java/seedu/address/logic/parser/SearchStudentCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SearchStudentCommandParserTest.java index d68f3e2ab53..7734a928adb 100644 --- a/src/test/java/seedu/address/logic/parser/SearchStudentCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/SearchStudentCommandParserTest.java @@ -34,7 +34,7 @@ public void parse_emptyArg_throwsParseException() { } @Test - public void parse_validArgs_returnsFindCommand() { + public void parse_validArgs_returnsSearchStudentCommand() { // valid name SearchStudentCommand expectedSearchStudentCommand = new SearchStudentCommand(new NameContainsKeywordPredicate(BOB.getName().fullName)); @@ -50,7 +50,6 @@ public void parse_validArgs_returnsFindCommand() { new SearchStudentCommand(new EmailContainsKeywordPredicate(BOB.getEmail().value)); assertParseSuccess(parser, EMAIL_DESC_BOB, expectedSearchStudentCommand); - // extended preamble expectedSearchStudentCommand = new SearchStudentCommand(new NameContainsKeywordPredicate(BOB.getName().fullName)); diff --git a/src/test/java/seedu/address/logic/parser/SortStudentCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SortStudentCommandParserTest.java new file mode 100644 index 00000000000..80f8116c4d5 --- /dev/null +++ b/src/test/java/seedu/address/logic/parser/SortStudentCommandParserTest.java @@ -0,0 +1,68 @@ +package seedu.address.logic.parser; + +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_INDEX; +import static seedu.address.logic.parser.CliSyntax.PREFIX_SORT_BY; +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.logic.Messages; +import seedu.address.logic.commands.SortStudentCommand; + +/** + * Contains unit tests for SortStudentCommandParser. + */ +public class SortStudentCommandParserTest { + + private SortStudentCommandParser parser = new SortStudentCommandParser(); + + @Test + public void parse_emptyArg_throwsParseException() { + assertParseFailure(parser, " ", + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + } + + @Test + public void parse_validArgs_returnsSortStudentCommand() { + // valid name + SortStudentCommand command = new SortStudentCommand("name"); + assertParseSuccess(parser, " " + PREFIX_SORT_BY + "name", command); + + // valid name + command = new SortStudentCommand("id"); + assertParseSuccess(parser, " " + PREFIX_SORT_BY + "id", command); + + // valid name + command = new SortStudentCommand("email"); + assertParseSuccess(parser, " " + PREFIX_SORT_BY + "email", command); + + // case-insensitive + command = new SortStudentCommand("name"); + assertParseSuccess(parser, " " + PREFIX_SORT_BY + "NaMe", command); + + // extended preamble + command = new SortStudentCommand("id"); + assertParseSuccess(parser, " " + PREFIX_SORT_BY + "id ", command); + } + + @Test + public void parse_invalidArgs_failure() { + // sort by prefix present but missing input + assertParseFailure(parser, " " + PREFIX_SORT_BY, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + + // missing prefix + assertParseFailure(parser, "", + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + + // invalid prefix + assertParseFailure(parser, " " + PREFIX_INDEX, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortStudentCommand.MESSAGE_USAGE)); + + // duplicate prefix + assertParseFailure(parser, " " + PREFIX_SORT_BY + "name " + PREFIX_SORT_BY + "id", + Messages.getErrorMessageForDuplicatePrefixes(PREFIX_SORT_BY)); + } +} diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java index ca7759f40aa..119269f2c0a 100644 --- a/src/test/java/seedu/address/model/AddressBookTest.java +++ b/src/test/java/seedu/address/model/AddressBookTest.java @@ -4,14 +4,17 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY; +import static seedu.address.logic.commands.CommandTestUtil.VALID_STUDENT_ID_AMY; import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.AMY; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.junit.jupiter.api.Test; @@ -83,11 +86,62 @@ public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() { assertTrue(addressBook.hasPerson(editedAlice)); } + @Test + public void hasPersonWithEmail_nullEmail_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> addressBook.hasPersonWithEmail(null)); + } + @Test + public void hasPersonWithEmail_personInAddressBook_returnsTrue() { + addressBook.addPerson(AMY); + assertTrue(addressBook.hasPersonWithEmail(AMY.getEmail())); + } + + @Test + public void hasPersonWithEmail_personNotInAddressBook_returnsFalse() { + assertFalse(addressBook.hasPersonWithEmail(AMY.getEmail())); + } + + @Test + public void hasPersonWithEmail_differentPersonWithSameEmail_returnsTrue() { + addressBook.addPerson(AMY); + Person alice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_AMY) + .build(); + assertTrue(addressBook.hasPersonWithEmail(alice.getEmail())); + } + + @Test + public void hasPersonWithStudentId_nullStudentId_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> addressBook.hasPersonWithStudentId(null)); + } + @Test + public void hasPersonWithStudentId_personInAddressBook_returnsTrue() { + addressBook.addPerson(AMY); + assertTrue(addressBook.hasPersonWithStudentId(AMY.getStudentId())); + } + + @Test + public void hasPersonWithStudentId_personNotInAddressBook_returnsFalse() { + assertFalse(addressBook.hasPersonWithStudentId(AMY.getStudentId())); + } + + @Test + public void hasPersonWithStudentId_differentPersonWithSameStudentId_returnsTrue() { + addressBook.addPerson(AMY); + Person alice = new PersonBuilder(ALICE).withStudentId(VALID_STUDENT_ID_AMY) + .build(); + assertTrue(addressBook.hasPersonWithStudentId(alice.getStudentId())); + } + @Test public void getPersonList_modifyList_throwsUnsupportedOperationException() { assertThrows(UnsupportedOperationException.class, () -> addressBook.getPersonList().remove(0)); } + @Test + public void getSortedPersonList_modifyList_throwsUnsupportedOperationException() { + + } + @Test public void toStringMethod() { String expected = AddressBook.class.getCanonicalName() + "{persons=" + addressBook.getPersonList() + "}"; @@ -99,6 +153,8 @@ public void toStringMethod() { */ private static class AddressBookStub implements ReadOnlyAddressBook { private final ObservableList persons = FXCollections.observableArrayList(); + private ObservableList sortedPersons; + AddressBookStub(Collection persons) { this.persons.setAll(persons); } @@ -113,6 +169,16 @@ public ObservableList getModuleList() { return null; } + @Override + public void setSortedPersonList(Comparator comparator) { + sortedPersons = FXCollections.observableArrayList(); + } + + @Override + public ObservableList getSortedPersonList() { + return sortedPersons; + } + @Override public boolean hasModule(ModuleCode moduleCode) { return false; diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 7547d3af800..d1cbd6b3886 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -7,6 +7,7 @@ import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.AMY; import static seedu.address.testutil.TypicalPersons.BENSON; import java.nio.file.Path; @@ -91,6 +92,21 @@ public void hasPerson_personInAddressBook_returnsTrue() { assertTrue(modelManager.hasPerson(ALICE)); } + @Test + public void hasPersonWithEmail_nullEmail_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> modelManager.hasPersonWithEmail(null)); + } + @Test + public void hasPersonWithEmail_personInAddressBook_returnsTrue() { + modelManager.addPerson(AMY); + assertTrue(modelManager.hasPersonWithEmail(AMY.getEmail())); + } + + @Test + public void hasPersonWithEmail_personNotInAddressBook_returnsFalse() { + assertFalse(modelManager.hasPersonWithEmail(AMY.getEmail())); + } + @Test public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() { assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0)); diff --git a/src/test/java/seedu/address/ui/MainWindowTest.java b/src/test/java/seedu/address/ui/MainWindowTest.java index f9b60892088..9f633098d0e 100644 --- a/src/test/java/seedu/address/ui/MainWindowTest.java +++ b/src/test/java/seedu/address/ui/MainWindowTest.java @@ -14,4 +14,11 @@ void useModuleView() { assertTrue(MainWindow.useModuleView("/delete_class module/CS2103T tutorial/T09")); assertFalse(MainWindow.useModuleView("/list_students")); } + + @Test + void useSortedView() { + assertTrue(MainWindow.useSortedView("/sort_student")); + assertTrue(MainWindow.useSortedView("/sort_student by/name")); + assertTrue(MainWindow.useSortedView("/sort_student by/EMaiL")); + } }