Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Teams feature #85

Merged
merged 12 commits into from
Mar 31, 2024
6 changes: 3 additions & 3 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ This section describes some noteworthy details on how certain features are imple

### Command history feature

This feature saves previously entered commands so that the user can easily view them again.
This feature saves previously entered commands so that the user can easily view them again.

#### Steps to trigger
1. User focuses the command input.
Expand All @@ -229,7 +229,7 @@ The following sequence diagram shows what happens as the user double clicks on t

### \[Proposed\] Undo/redo feature

#### Proposed Implementation
#### Proposed Implementation

The proposed undo/redo mechanism is facilitated by `VersionedCodeConnect`. It extends `CodeConnect` with an undo/redo
history, stored internally as `codeConnectStateList` and `currentStatePointer`. Additionally, it implements the
Expand Down Expand Up @@ -540,7 +540,7 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli

* 1b. There are no contacts in the list that match the criteria.
* 1b1. CodeConnect shows an empty list.
Use case ends.
Use case ends.

**Use case: UC08 - Sending an email to a specific contact**

Expand Down
2 changes: 1 addition & 1 deletion docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# CodeConnect User Guide
Hello fellow student developers! Welcome to your one-stop shop for managing developers' contacts!

Codeconnect is a **developer-first networking app** for student developers to keep track of and reach out easily to other student developers, so they form teams for hackathons.
Codeconnect is a **developer-first networking app** for student developers to keep track of and reach out easily to other student developers, so they form teams for hackathons.

We are **optimized for use via a Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, CC can get your contact management tasks done faster than traditional GUI apps.

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/seedu/address/logic/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import seedu.address.logic.parser.Prefix;
import seedu.address.model.contact.Contact;
import seedu.address.model.team.Team;

/**
* Container for user visible messages.
Expand All @@ -15,6 +16,7 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_CONTACT_DISPLAYED_INDEX = "The contact index provided is invalid";
public static final String MESSAGE_INVALID_TEAM_DISPLAYED_INDEX = "The team index provided is invalid";
public static final String MESSAGE_CONTACT_LISTED_OVERVIEW = "%1$d contacts listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
Expand Down Expand Up @@ -54,4 +56,13 @@ public static String format(Contact contact) {
return builder.toString();
}

/**
* Formats the {@code team} for display to the user.
*/
public static String format(Team team) {
final StringBuilder builder = new StringBuilder();
builder.append(team.getName());
team.getMembers().forEach(builder::append);
return builder.toString();
}
}
73 changes: 73 additions & 0 deletions src/main/java/seedu/address/logic/commands/AddTeamCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.TeamCommandsParser;
import seedu.address.model.Model;
import seedu.address.model.team.Team;

/**
* Adds a team to the address book.
*/
public class AddTeamCommand extends Command {
public static final String COMMAND_WORD = "add";

public static final String MESSAGE_USAGE = TeamCommandsParser.COMMAND_WORD + " "
+ COMMAND_WORD + " " + PREFIX_NAME + "TEAM_NAME" + ": Adds a team to the address book. \n"
+ "Parameters: "
+ PREFIX_NAME + "TEAM_NAME (only alphanumeric characters)\n"
+ "Example: " + TeamCommandsParser.COMMAND_WORD + " " + COMMAND_WORD + " "
+ PREFIX_NAME + "NUSHack2024 ";


public static final String MESSAGE_SUCCESS = "New team added: %1$s";
public static final String MESSAGE_DUPLICATE_TEAM = "A team with this name already exists in CodeConnect";

private final Team toAdd;

/**
* Creates an AddCommand to add the specified {@code Contact}
*/
public AddTeamCommand(Team team) {
requireNonNull(team);
toAdd = team;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);

if (model.hasTeam(toAdd)) {
throw new CommandException(MESSAGE_DUPLICATE_TEAM);
}

model.addTeam(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(toAdd)));
}

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

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

AddTeamCommand otherAddTeamCommand = (AddTeamCommand) other;
return toAdd.equals(otherAddTeamCommand.toAdd);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("toAdd", toAdd)
.toString();
}
}
69 changes: 69 additions & 0 deletions src/main/java/seedu/address/logic/commands/DeleteTeamCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;

import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.TeamCommandsParser;
import seedu.address.model.Model;
import seedu.address.model.team.Team;

/**
* Deletes a team identified using it's displayed index from address book.
*/
public class DeleteTeamCommand extends Command {
public static final String COMMAND_WORD = "delete";

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

public static final String MESSAGE_DELETE_TEAM_SUCCESS = "Deleted Team: %1$s";

private final Index targetIndex;

public DeleteTeamCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Team> teamList = model.getCodeConnect().getTeamList();

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

Team teamToDelete = teamList.get(targetIndex.getZeroBased());
model.deleteTeam(teamToDelete);
return new CommandResult(String.format(MESSAGE_DELETE_TEAM_SUCCESS, Messages.format(teamToDelete)));
}

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

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

DeleteTeamCommand otherDeleteCommand = (DeleteTeamCommand) other;
return targetIndex.equals(otherDeleteCommand.targetIndex);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("targetIndex", targetIndex)
.toString();
}
}
73 changes: 73 additions & 0 deletions src/main/java/seedu/address/logic/commands/ListTeamCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;

import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.TeamCommandsParser;
import seedu.address.model.Model;
import seedu.address.model.contact.Contact;
import seedu.address.model.team.Team;

/**
* Lists all contacts belonging to a team in the address book to the user.
*/
public class ListTeamCommand extends Command {
public static final String COMMAND_WORD = "";

public static final String MESSAGE_USAGE = TeamCommandsParser.COMMAND_WORD + " TEAM_INDEX"
+ ": Lists the members of the team identified by the index number used in the displayed team list.\n"
+ "Parameters: TEAM_INDEX (must be a positive integer)\n"
+ "Example: " + TeamCommandsParser.COMMAND_WORD + " 1";

public static final String MESSAGE_SUCCESS = "Listing contacts for team: ";

private final Index targetIndex;

public ListTeamCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Team> teamList = model.getCodeConnect().getTeamList();

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

Team teamToList = teamList.get(targetIndex.getZeroBased());
List<Contact> teamMembers = teamToList.getMembers();

model.updateFilteredContactList(a -> teamMembers.stream().anyMatch(a::isSameContact));

return new CommandResult(MESSAGE_SUCCESS + teamToList.getName());
}

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

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

ListTeamCommand otherListTeamCommand = (ListTeamCommand) other;
return targetIndex.equals(otherListTeamCommand.targetIndex);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("targetIndex", targetIndex)
.toString();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
import static seedu.address.logic.parser.CliSyntax.PREFIX_GITHUB_USERNAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PROFILE_PICTURE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TECH_STACK;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PROFILE_PICTURE;


import java.util.Set;
import java.util.stream.Stream;

import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.contact.Address;
import seedu.address.model.contact.Contact;
import seedu.address.model.contact.Email;
import seedu.address.model.contact.GitHubUsername;
import seedu.address.model.contact.Name;
import seedu.address.model.contact.Contact;
import seedu.address.model.contact.Phone;
import seedu.address.model.contact.ProfilePicture;
import seedu.address.model.tag.Tag;
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/seedu/address/logic/parser/AddTeamCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;

import seedu.address.logic.commands.AddTeamCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.contact.Name;
import seedu.address.model.team.Team;

/**
* Parses the given {@code String} of arguments in the context of the AddTeamCommand
* and returns an AddTeamCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public class AddTeamCommandParser implements Parser<AddTeamCommand> {
@Override
public AddTeamCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_NAME);

if (!argMultimap.getValue(PREFIX_NAME).isPresent()
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTeamCommand.MESSAGE_USAGE));
}

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME);

Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());

return new AddTeamCommand(new Team(name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();

case TeamCommandsParser.COMMAND_WORD:
return TeamCommandsParser.parse(arguments);

default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class ParserUtil {
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
requireNonNull(oneBasedIndex);
String trimmedIndex = oneBasedIndex.trim();
if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
throw new ParseException(MESSAGE_INVALID_INDEX);
Expand Down
Loading
Loading