diff --git a/src/main/java/seedu/hireme/logic/commands/StatusCommand.java b/src/main/java/seedu/hireme/logic/commands/StatusCommand.java
new file mode 100644
index 00000000000..bc8d6297b8b
--- /dev/null
+++ b/src/main/java/seedu/hireme/logic/commands/StatusCommand.java
@@ -0,0 +1,110 @@
+package seedu.hireme.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.hireme.commons.core.index.Index;
+import seedu.hireme.logic.Messages;
+import seedu.hireme.logic.commands.exceptions.CommandException;
+import seedu.hireme.model.Model;
+import seedu.hireme.model.internshipapplication.InternshipApplication;
+import seedu.hireme.model.internshipapplication.Status;
+
+/**
+ * Changes the status of an internship application identified using its displayed index.
+ */
+public class StatusCommand extends Command {
+
+ /** Command word for accepting an application. */
+ public static final String COMMAND_WORD_ACCEPT = "/accept";
+
+ /** Command word for marking an application as pending. */
+ public static final String COMMAND_WORD_PENDING = "/pending";
+
+ /** Command word for rejecting an application. */
+ public static final String COMMAND_WORD_REJECT = "/reject";
+
+ /**
+ * Message to display for command usage instructions.
+ */
+ public static final String MESSAGE_USAGE = COMMAND_WORD_ACCEPT
+ + " / " + COMMAND_WORD_PENDING + " / " + COMMAND_WORD_REJECT
+ + ": Changes the status of the internship application identified by "
+ + "the index number used in the displayed list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD_ACCEPT + " 1";
+
+ /**
+ * Message to display upon successful status update.
+ */
+ public static final String MESSAGE_STATUS_CHANGE_SUCCESS = "Updated status of internship application: %1$s to %2$s";
+
+ private final Index targetIndex;
+ private final Status newStatus;
+
+ /**
+ * Constructs a {@code StatusCommand}.
+ *
+ * @param targetIndex The index of the internship application to update.
+ * @param newStatus The new status to set for the internship application.
+ */
+ public StatusCommand(Index targetIndex, Status newStatus) {
+ this.targetIndex = targetIndex;
+ this.newStatus = newStatus;
+ }
+
+ /**
+ * Executes the command to update the status of an internship application.
+ *
+ * @param model The model containing the list of internship applications.
+ * @return A {@code CommandResult} indicating the result of the status update.
+ * @throws CommandException If the target index is invalid.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_INTERNSHIP_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipApplicationToUpdate = lastShownList.get(targetIndex.getZeroBased());
+ internshipApplicationToUpdate.setStatus(newStatus);
+ return new CommandResult(String.format(MESSAGE_STATUS_CHANGE_SUCCESS,
+ Messages.format(internshipApplicationToUpdate), newStatus.getValue()));
+ }
+
+ /**
+ * Checks if this command is equal to another object.
+ *
+ * @param other The other object to compare.
+ * @return True if both objects are the same or have the same target index and new status, false otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof StatusCommand)) {
+ return false;
+ }
+
+ StatusCommand otherStatusCommand = (StatusCommand) other;
+ return targetIndex.equals(otherStatusCommand.targetIndex)
+ && newStatus.equals(otherStatusCommand.newStatus);
+ }
+
+ /**
+ * Returns the string representation of this command.
+ *
+ * @return A string representing this {@code StatusCommand}.
+ */
+ @Override
+ public String toString() {
+ return StatusCommand.class.getCanonicalName()
+ + "{targetIndex=" + targetIndex + ", newStatus=" + newStatus.getValue() + "}";
+ }
+}
diff --git a/src/main/java/seedu/hireme/logic/parser/AddressBookParser.java b/src/main/java/seedu/hireme/logic/parser/AddressBookParser.java
index 2f446855cc0..dcb7d1c9c1b 100644
--- a/src/main/java/seedu/hireme/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/hireme/logic/parser/AddressBookParser.java
@@ -16,8 +16,10 @@
import seedu.hireme.logic.commands.FindCommand;
import seedu.hireme.logic.commands.HelpCommand;
import seedu.hireme.logic.commands.ListCommand;
+import seedu.hireme.logic.commands.StatusCommand;
import seedu.hireme.logic.parser.exceptions.ParseException;
import seedu.hireme.model.internshipapplication.InternshipApplication;
+import seedu.hireme.model.internshipapplication.Status;
/**
* Parses user input.
@@ -59,6 +61,15 @@ public Command parseCommand(String userInput) throws Pars
case DeleteCommand.COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);
+ case StatusCommand.COMMAND_WORD_ACCEPT:
+ return new StatusCommandParser(Status.ACCEPTED).parse(arguments);
+
+ case StatusCommand.COMMAND_WORD_PENDING:
+ return new StatusCommandParser(Status.PENDING).parse(arguments);
+
+ case StatusCommand.COMMAND_WORD_REJECT:
+ return new StatusCommandParser(Status.REJECTED).parse(arguments);
+
case ClearCommand.COMMAND_WORD:
return new ClearCommand();
diff --git a/src/main/java/seedu/hireme/logic/parser/StatusCommandParser.java b/src/main/java/seedu/hireme/logic/parser/StatusCommandParser.java
new file mode 100644
index 00000000000..7ce1f769cb8
--- /dev/null
+++ b/src/main/java/seedu/hireme/logic/parser/StatusCommandParser.java
@@ -0,0 +1,43 @@
+package seedu.hireme.logic.parser;
+
+import static seedu.hireme.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.hireme.commons.core.index.Index;
+import seedu.hireme.logic.commands.StatusCommand;
+import seedu.hireme.logic.parser.exceptions.ParseException;
+import seedu.hireme.model.internshipapplication.Status;
+
+/**
+ * Parses input arguments and creates a new StatusCommand object
+ */
+public class StatusCommandParser implements Parser {
+
+ private final Status status;
+
+ public StatusCommandParser(Status status) {
+ this.status = status;
+ }
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the StatusCommand
+ * and returns a StatusCommand object for execution.
+ * @throws ParseException if the user input does not conform to the expected format
+ */
+ public StatusCommand parse(String args) throws ParseException {
+ try {
+ // Parse index from the arguments
+ Index index = ParserUtil.parseIndex(args.trim());
+
+ // Ensure the status is one of the allowed values (PENDING, ACCEPTED, REJECTED)
+ if (status == null || !(status == Status.PENDING || status == Status.ACCEPTED
+ || status == Status.REJECTED)) {
+ throw new ParseException(Status.MESSAGE_CONSTRAINTS);
+ }
+
+ return new StatusCommand(index, status);
+
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, StatusCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/hireme/model/ModelManager.java b/src/main/java/seedu/hireme/model/ModelManager.java
index d1a7ea44608..a95e89583a9 100644
--- a/src/main/java/seedu/hireme/model/ModelManager.java
+++ b/src/main/java/seedu/hireme/model/ModelManager.java
@@ -131,16 +131,20 @@ public void updateFilteredList(Predicate predicate) {
@Override
public boolean equals(Object other) {
-
+ // Check if the objects are the same instance
if (other == this) {
return true;
}
- // instanceof handles nulls
- if (!(other instanceof ModelManager> otherModelManager)) {
+ // Check if the other object is an instance of ModelManager and not null
+ if (!(other instanceof ModelManager>)) {
return false;
}
+ // Cast the other object to ModelManager
+ ModelManager> otherModelManager = (ModelManager>) other;
+
+ // Compare the state of addressBook, userPrefs, and filtered lists
return addressBook.equals(otherModelManager.addressBook)
&& userPrefs.equals(otherModelManager.userPrefs)
&& filtered.equals(otherModelManager.filtered);
diff --git a/src/main/java/seedu/hireme/model/internshipapplication/InternshipApplication.java b/src/main/java/seedu/hireme/model/internshipapplication/InternshipApplication.java
index 8b5805d1445..7ae5ab14edb 100644
--- a/src/main/java/seedu/hireme/model/internshipapplication/InternshipApplication.java
+++ b/src/main/java/seedu/hireme/model/internshipapplication/InternshipApplication.java
@@ -17,7 +17,7 @@ public class InternshipApplication implements HireMeComparable
+ * The deep copy ensures that the new {@code InternshipApplication} is a completely independent
+ * copy, meaning any changes to the new object will not affect the original object.
+ * This method creates a new {@code Company} instance to avoid sharing mutable state, but since
+ * {@code String} and {@code Status} are immutable, those are shared directly.
+ *
+ *
+ * @return A new {@code InternshipApplication} instance with the same values as this instance.
+ */
+ public InternshipApplication deepCopy() {
+ return new InternshipApplication(
+ new Company(this.company.getEmail(), this.company.getName()), // Deep copy of mutable Company
+ this.dateOfApplication, // String is immutable, safe to share reference
+ this.role, // String is immutable, safe to share reference
+ this.status // Status is immutable (enum), safe to share reference
+ );
+ }
}
diff --git a/src/test/java/seedu/hireme/logic/commands/StatusCommandTest.java b/src/test/java/seedu/hireme/logic/commands/StatusCommandTest.java
new file mode 100644
index 00000000000..6126c2fd621
--- /dev/null
+++ b/src/test/java/seedu/hireme/logic/commands/StatusCommandTest.java
@@ -0,0 +1,101 @@
+package seedu.hireme.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.hireme.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.hireme.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.hireme.logic.commands.CommandTestUtil.showInternshipApplicationAtIndex;
+import static seedu.hireme.testutil.TypicalIndexes.INDEX_FIRST_INTERNSHIP_APPLICATION;
+import static seedu.hireme.testutil.TypicalIndexes.INDEX_SECOND_INTERNSHIP_APPLICATION;
+import static seedu.hireme.testutil.TypicalInternshipApplications.getClonedAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.hireme.commons.core.index.Index;
+import seedu.hireme.logic.Messages;
+import seedu.hireme.model.Model;
+import seedu.hireme.model.ModelManager;
+import seedu.hireme.model.UserPrefs;
+import seedu.hireme.model.internshipapplication.InternshipApplication;
+import seedu.hireme.model.internshipapplication.Status;
+
+public class StatusCommandTest {
+
+ private Model model = new ModelManager<>(getClonedAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_validIndexUnfilteredList_success() {
+ Model clonedModel = new ModelManager<>(getClonedAddressBook(), new UserPrefs());
+
+ InternshipApplication internshipApplicationToUpdate = clonedModel
+ .getFilteredList().get(INDEX_FIRST_INTERNSHIP_APPLICATION.getZeroBased());
+
+ StatusCommand statusCommand = new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.ACCEPTED);
+
+ String expectedMessage = String.format(StatusCommand.MESSAGE_STATUS_CHANGE_SUCCESS,
+ Messages.format(internshipApplicationToUpdate), Status.ACCEPTED.getValue());
+
+ ModelManager expectedModel = new ModelManager<>(getClonedAddressBook(), new UserPrefs());
+
+ InternshipApplication updatedApplication = new InternshipApplication(
+ internshipApplicationToUpdate.getCompany(),
+ internshipApplicationToUpdate.getDateOfApplication(),
+ internshipApplicationToUpdate.getRole(),
+ Status.ACCEPTED
+ );
+
+ expectedModel.setItem(internshipApplicationToUpdate, updatedApplication);
+
+ assertCommandSuccess(statusCommand, clonedModel, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_invalidIndexUnfilteredList_throwsCommandException() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredList().size() + 1);
+ StatusCommand statusCommand = new StatusCommand(outOfBoundIndex, Status.ACCEPTED);
+
+ assertCommandFailure(statusCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void execute_invalidIndexFilteredList_throwsCommandException() {
+ showInternshipApplicationAtIndex(model, INDEX_FIRST_INTERNSHIP_APPLICATION);
+
+ Index outOfBoundIndex = INDEX_SECOND_INTERNSHIP_APPLICATION;
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getList().size());
+
+ StatusCommand statusCommand = new StatusCommand(outOfBoundIndex, Status.PENDING);
+
+ assertCommandFailure(statusCommand, model, Messages.MESSAGE_INVALID_INTERNSHIP_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ StatusCommand statusFirstCommand = new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.ACCEPTED);
+ StatusCommand statusSecondCommand = new StatusCommand(INDEX_SECOND_INTERNSHIP_APPLICATION, Status.PENDING);
+
+ assertTrue(statusFirstCommand.equals(statusFirstCommand));
+
+ StatusCommand statusFirstCommandCopy = new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.ACCEPTED);
+ assertTrue(statusFirstCommand.equals(statusFirstCommandCopy));
+
+ assertFalse(statusFirstCommand.equals(1));
+ assertFalse(statusFirstCommand.equals(null));
+ assertFalse(statusFirstCommand.equals(statusSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Index targetIndex = Index.fromOneBased(1);
+ StatusCommand statusCommand = new StatusCommand(targetIndex, Status.ACCEPTED);
+ String expected = StatusCommand.class.getCanonicalName()
+ + "{targetIndex=" + targetIndex + ", newStatus=" + Status.ACCEPTED + "}";
+ assertEquals(expected, statusCommand.toString());
+ }
+
+ private void showNoInternshipApplication(Model model) {
+ model.updateFilteredList(p -> false);
+ assertTrue(model.getFilteredList().isEmpty());
+ }
+}
diff --git a/src/test/java/seedu/hireme/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/hireme/logic/parser/AddressBookParserTest.java
index ad33bf9e5be..8f2a13271b8 100644
--- a/src/test/java/seedu/hireme/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/hireme/logic/parser/AddressBookParserTest.java
@@ -19,12 +19,15 @@
import seedu.hireme.logic.commands.FindCommand;
import seedu.hireme.logic.commands.HelpCommand;
import seedu.hireme.logic.commands.ListCommand;
+import seedu.hireme.logic.commands.StatusCommand;
import seedu.hireme.logic.parser.exceptions.ParseException;
import seedu.hireme.model.internshipapplication.InternshipApplication;
import seedu.hireme.model.internshipapplication.NameContainsKeywordsPredicate;
+import seedu.hireme.model.internshipapplication.Status;
import seedu.hireme.testutil.InternshipApplicationBuilder;
import seedu.hireme.testutil.InternshipApplicationUtil;
+
public class AddressBookParserTest {
private final AddressBookParser parser = new AddressBookParser();
@@ -87,4 +90,22 @@ public void parseCommand_unrecognisedInput_throwsParseException() {
public void parseCommand_unknownCommand_throwsParseException() {
assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
}
+
+ @Test
+ public void parseCommand_statusAccept_success() throws Exception {
+ StatusCommand command = (StatusCommand) parser.parseCommand("/accept 1");
+ assertEquals(new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.ACCEPTED), command);
+ }
+
+ @Test
+ public void parseCommand_statusPending_success() throws Exception {
+ StatusCommand command = (StatusCommand) parser.parseCommand("/pending 1");
+ assertEquals(new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.PENDING), command);
+ }
+
+ @Test
+ public void parseCommand_statusReject_success() throws Exception {
+ StatusCommand command = (StatusCommand) parser.parseCommand("/reject 1");
+ assertEquals(new StatusCommand(INDEX_FIRST_INTERNSHIP_APPLICATION, Status.REJECTED), command);
+ }
}
diff --git a/src/test/java/seedu/hireme/logic/parser/CommandParserTestUtil.java b/src/test/java/seedu/hireme/logic/parser/CommandParserTestUtil.java
index c8299de1935..62ca4cde196 100644
--- a/src/test/java/seedu/hireme/logic/parser/CommandParserTestUtil.java
+++ b/src/test/java/seedu/hireme/logic/parser/CommandParserTestUtil.java
@@ -35,7 +35,10 @@ public static void assertParseFailure(Parser extends Command getTypicalAddressBook() {
return ab;
}
+ public static AddressBook getClonedAddressBook() {
+ AddressBook clonedAb = new AddressBook<>();
+ for (InternshipApplication internshipApp : getTypicalInternshipApplications()) {
+ clonedAb.addItem(internshipApp.deepCopy());
+ }
+ return clonedAb;
+ }
+
public static List getTypicalInternshipApplications() {
return new ArrayList<>(Arrays.asList(APPLE, BOFA, CITIBANK, DELL, EY, FIGMA, YAHOO));
}