diff --git a/.gitignore b/.gitignore index 71c9194e8bd..f85cff43711 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ src/main/resources/docs/ /out/ /*.iml +# Gradle run bin (on VS code) +/bin + # Storage/log files /data/ /config.json diff --git a/README.md b/README.md index 13f5c77403f..991c465a237 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,39 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) +[![CI Status](https://github.com/AY2122S2-CS2103T-W14-3/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103T-W14-3/tp/actions) + + + ![Ui](docs/images/Ui.png) -* This is **a sample project for Software Engineering (SE) students**.
- Example usages: - * as a starting point of a course project (as opposed to writing everything from scratch) - * as a case study -* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details. - * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big. - * It comes with a **reasonable level of user and developer documentation**. -* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...). -* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**. -* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info. +# InternBuddy +InternBuddy is a desktop app for managing companies for internships, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). +If you can type fast, InternBuddy can get your internship management deliverables done faster than traditional GUI apps. + +InternBuddy provides you a way to plan and organize all your internship details on a single application, with intuitive +UI to make your Job Seeking journey a smooth road. + +InternBuddy allows you to: +* Store and manage Companies +* Manage Contacts + * For example: Hiring Manager Contact Details +* Manage Events + * For example: Interviews and Online Assessments + +For more detailed information on how to use the application, click on [User Guide](docs/UserGuide.md) + +--- + +### More Information about the Project +* InternBuddy is an **ongoing** collaborated Software Development Project maintained by + * Albert Sutiono + * Edward Alvin + * Muhammad Radhya + * Steven Gabriel Kho Chua +* InternBuddy is a brown-field project which is forked from [Address Book 3](https://github.com/nus-cs2103-AY2122S2/tp), a software development project (around 6 KLoC) which provide a baseline for InternBuddy. +* You can look into our [Developer Guide](docs/DeveloperGuide.md) for more details about the codebase. + +### Main Language and Tools used: +

+Java +JavaFX +

diff --git a/build.gradle b/build.gradle index be2d2905dde..3e4799376a6 100644 --- a/build.gradle +++ b/build.gradle @@ -70,3 +70,7 @@ shadowJar { } defaultTasks 'clean', 'test' + +run { + enableAssertions = true +} diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..d1abac4842d 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -5,55 +5,56 @@ title: About Us We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg). -You can reach us at the email `seer[at]comp.nus.edu.sg` - ## Project team +### Albert Sutiono -### John Doe + - +[[github](https://github.com/albertsutz)] +[[linkedin](https://www.linkedin.com/in/albert-sutiono/)] +[[portfolio](./team/albertsutz.md)] -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +* Role: Developer +* Responsibilities: In charge of Code Review and `find`, `edit` commands implementation, Testing +
-* Role: Project Advisor +I am an eager Y2 computer science undergraduate with the desire to learn and improve myself in this field. I aim to delve deeper into the world of software engineering and cybersecurity which address and solve real world problems with the focus on privacy and data security. -### Jane Doe +### Edward Alvin - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/theprevailingone)] [[linkedin](https://www.linkedin.com/in/edwardalvin/)] [[portfolio](./team/theprevailingone.md)] -* Role: Team Lead -* Responsibilities: UI +* Role: Developer +* Responsibilities: UG main handler, sort command implementation along with parser, testings, and documentation -### Johnny Doe +Computer Science undergraduate passionate about software engineering and game development. Capable developer, having devised and developed multiple projects. Proficient in a range of modern technologies including Python, Javascript and Java. Interested in UI/UX Design and Data Science. Looking for new opportunities and challenges. - +### Steven Chua -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] + -* Role: Developer -* Responsibilities: Data +[[homepage](https://www.linkedin.com/in/stevengkchua)] +[[github](http://github.com/graphcalibur)] +[[portfolio](team/graphcalibur.md)] -### Jean Doe +* Role: Developer +* Responsibilities: Repository setup, issue management, archive feature implementation, testing - +I'm a Year 2 Computer Science undergraduate science with a passion for technology, games, and cybersecurity. +I'm always looking for ways to improve my skills and widen my knowledge. -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +### Muhammad Radhya Fawza -* Role: Developer -* Responsibilities: Dev Ops + Threading + -### James Doe +[[github](https://github.com/mradhyaf)] +[[portofolio](./team/mradhyaf.md)] - +* Role: Developer +* Responsibilities: User Interface -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +I am a software engineer with a passion for free software—software that respects user's freedom. I am currently a +second-year computer science undergraduate interested in UI/UX Design. -* Role: Developer -* Responsibilities: UI diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 46eae8ee565..ffb668eaa0b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -9,7 +9,8 @@ title: Developer Guide ## **Acknowledgements** -* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +* InternBuddy is a brown-field project which is forked from [Address Book 3](https://github.com/nus-cs2103-AY2122S2/tp), a software development project (around 6 KLoC) which provide a baseline for InternBuddy. +* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5) -------------------------------------------------------------------------------------------------------------------- @@ -23,7 +24,7 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md).
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams. +:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
### Architecture @@ -36,7 +37,7 @@ Given below is a quick overview of main components and how they interact with ea **Main components of the architecture** -**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for, +**`Main`** has two classes called [`Main`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for, * At app launch: Initializes the components in the correct sequence, and connects them up with each other. * At shut down: Shuts down the components and invokes cleanup methods where necessary. @@ -61,7 +62,10 @@ Each of the four main components (also shown in the diagram above), * defines its *API* in an `interface` with the same name as the Component. * implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point. -For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below. +For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using +the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component +through its interface rather than the concrete class (reason: to prevent outside components being coupled to the +implementation of a component), as illustrated in the (partial) class diagram below. @@ -69,24 +73,35 @@ The sections below give more details of each component. ### UI component -The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) +The **API** of this component is specified in [`Ui.java`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/ui/Ui.java) ![Structure of the UI Component](images/UiClassDiagram.png) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `EntryListPanel`, +`StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which +captures the commonalities between classes that represent parts of the visible GUI. -The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) +The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files +that are in the `src/main/resources/view` folder. For example, the layout of the[`MainWindow`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/ui/MainWindow.java) +is specified in [`MainWindow.fxml`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/resources/view/MainWindow.fxml) + +The `UI` has 3 different `ListPanel` components: `PersonList`, `CompanyList`, and `EventList`. Only one of these lists +are shown at a time in the display. + +Notice as the application only shows one list at one time, `EntryListPanel` acts as a placeholder to contain +`PersonListPanel`, `CompanyListPanel`, or `EventListPanel`. The `UI` component, * executes user commands using the `Logic` component. * listens for changes to `Model` data so that the UI can be updated with the modified data. * keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. +* depends on some classes in the `Model` component, as it displays `Person`, `Company`, and `Event` objects +residing in the `Model`. ### Logic component -**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +**API** : [`Logic.java`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/logic/Logic.java) Here's a (partial) class diagram of the `Logic` component: @@ -102,7 +117,8 @@ The Sequence Diagram below illustrates the interactions within the `Logic` compo ![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png) -
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +
:information_source: **Note:** The lifeline for `DeleteCommandParser` +should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: @@ -110,32 +126,54 @@ Here are the other classes in `Logic` (omitted from the class diagram above) tha How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. +* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a +placeholder for the specific command name e.g., `DeleteCommandParser`) which uses the other classes shown above to parse + the user command and create a `XYZCommand` object (e.g., `DeleteCommand`) which the `AddressBookParser` returns back as +a `Command` object. +* All `XYZCommandParser` classes (e.g., `DeleteCommandParser`, `ListPersonCommandParser`, ...) inherit from the `Parser` interface +so that they can be treated similarly where possible e.g, during testing. ### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) +**API** : [`Model.java`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/model/Model.java) The `Model` component, -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. -* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) +* stores the address book data i.e., all `Entry` objects + * Each type of entry (`Company`, `Person`, and `Event`) is contained in their own `UniqueEntryList` objects. +* stores the currently 'selected' objects (e.g., results of a search query) as a separate _filtered_ list. + * Each type of entry (`Company`, `Person`, and `Event`) has their own filtered list + * These filtered lists are exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' +e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a +`ReadOnlyUserPref` objects. +* does not depend on any of the other three components (as the `Model` represents data entities of the domain, +they should make sense on their own without depending on other components) + +Here are the various classes that inherits from and is used by the `Entry` object: + + -
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+Note that the `CompanyName` object is actually just a `Name` object, so in effect `Person` and `Event` have two +`Name` objects: one for their name, and one for the name of the company they are attached to. - +Furthermore, the `CompanyName` +object must match an existing `Company` object in the `AddressBook`. + +
:information_source: **Note:** An alternative (arguably, a more OOP) model +is given below. It has a `Tag` list in the `AddressBook`, which `Entry` references. This allows `AddressBook` to only +require one `Tag` object per unique tag, instead of each `Entry` needing their own `Tag` objects.
+ +
### Storage component -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) +**API** : [`Storage.java`](https://github.com/AY2122S2-CS2103T-W14-3/tp/tree/master/src/main/java/seedu/address/storage/Storage.java) @@ -176,7 +214,7 @@ Step 2. The user executes `delete 5` command to delete the 5th person in the add ![UndoRedoState1](images/UndoRedoState1.png) -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +Step 3. The user executes `addc n/David …​` to add a new person. The `addc` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. ![UndoRedoState2](images/UndoRedoState2.png) @@ -207,11 +245,11 @@ The `redo` command does the opposite — it calls `Model#redoAddressBook()`,
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. +Step 5. The user then decides to execute the command `listc`. Commands that do not modify the address book, such as `listc`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. ![UndoRedoState4](images/UndoRedoState4.png) -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow. +Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `addc n/David …​` command. This is the behavior that most modern desktop applications follow. ![UndoRedoState5](images/UndoRedoState5.png) @@ -234,10 +272,220 @@ The following activity diagram summarizes what happens when a user executes a ne _{more aspects and alternatives to be added}_ -### \[Proposed\] Data archiving +### Archive Feature + +#### Design + +The main idea of the archive feature for InternBuddy is that archived entries will not show up when searching for entries +with the `find` or `list` or `sort` commands unless the user specifies that they specifically want to search for archived entries. +In this way, they function similarly to hidden files in many file managers. + +To handle this, the `list`, `find` and `sort` commands needed an extra parameter indicating the search type. For flexibility, +there were 3 kinds of search types: `UNARCHIVED_ONLY`, `ARCHIVED_ONLY`, and `ALL`. The user could still opt +not to explicitly pass a search type; in this case, the default behavior would be `UNARCHIVED_ONLY`. + +This extra parameter required the list commands, which previously had no parser, to use a `ListCommandParser` in order +to parse the needed search type. Because the parser would function almost the same for each of the list commands, only one +`ListCommandParser` object was created to handle the 3 kinds of list commands. This itself necessitated creating a +`ListCommand` object class that each of the 3 list command classes would inherit from, so that the `ListCommandParser` +could return any of the 3 list command classes for the `parse()` method. + +To deal with the actual archiving, each `Entry` object was given an `isArchived` attribute indicating if the entry +was archived or not. Predicates to check the value of the `isArchived` attribute of each entry could then be applied to the +filtered lists to filter out archived entries (or filter only archived entries). + +Finally, the `archive` command was designed to take only the index as the parameter. It would archive the entry specified +by the index that was in the currently displayed list. The `unarchive` command has a similar design. + +#### Implementation + +For the `archive` command: +1. The user executes `archive 3`. +2. This command is parsed to check if the given index is valid. If not, a `ParseException` is thrown. +3. Otherwise, the created `ArchiveCommand` object will execute `Model#archiveEntry(index, true)`. +4. The model will then retrieve the object from the currently displayed filtered list based on the `index` given and pass +this along with the boolean argument to`ReadOnlyAddressBook#setArchiveEvent()` (or `setArchiveCompany()` or `setArchivePerson()`) depending on +the value of `currentlyDisplayedListType` +5. The address book will then call `setArchiveEntry(object, true)` in the respective `UniqueEntryList`. +6. Finally, the `UniqueEntryList` will search for the passed object and if it exists (which it should unless a bug occurs), +it will call the `setArchived(true)` of the Entry. +7. Finally, the command calls `Model#updateCurrentlyDisplayedList(PREDICATE_SHOW_UNARCHIVED_ONLY)` to change the currently +displayed list to show all its unarchived entries. Note that in order to get the update to work properly, +`Model#updateCurrentlyDisplayedList(PREDICATE_ALL) must be called first. +8. The `CommandResult` of the `archive` command is returned. + +A similar process is performed with the `unarchive` command, but `Entry#setArchived()` is ultimately passed `false` instead of `true`. + +For one of the list commands, here is a sample process: +1. The user executes `listc` +2. The `ListCommandParser` object is creates with the appropriate `ListType` passed as a parameter to the constructor. +3. The `ListCommandParser` parses the command to see if the search type parameter is valid. If there is none, or if the +passed search type parameter is `unarchived`, `archived`, or `all`, the execution proceeds to 3). Otherwise, a +`ParseException` is thrown. +4. The `ListCommandParser` then creates the appropriate `ListCommand` object based on the `ListType` attribute. The +`ListCommand` object is created with a `SearchType` passed as the parameter. +5. When the `ListCommand` object is executed, it switches the displayed list to the proper one and applies the appropriate +predicate on it depending on the search type. +6. The `CommandResult` of the `find` command is returned. + +A simplified sequence diagram of the archive command is shown below. + +![ArchiveSequenceDiagram](images/ArchiveSequenceDiagram.png) + +### Sort Feature + +#### Design + +The main idea for the sort feature for InternBuddy is that entries can be sorted by the importance of the entry. In InternBuddy, the importance of a company or a person is based on the lexicographical order of the company or person's name. As for event, the importance of an event is based on the date of the event. The sort feature is capable of ordering the entries in ascending or descending order. + +The `sort` command functions similarly to its `list` counterpart in terms of display. Both the commands will display the entries accordingly depending on the entry type specified for the command. The difference is that the `sort` command will sort the entries according to the importance of the entry. + +Due to its similar nature to the `list` command, the `sort` command extends the `list` command to minimize re-implementing the same behaviour twice. This is also done to further enforce DRY. The `sort` command also has a `SearchType` parameter. The `SearchType` parameter is optional. The `sort` command takes in an additional `Ordering` parameter as well. The `Ordering` parameter is optional. the `Ordering` parameter allows the user to specify whether the entries should be sorted in ascending or descending order. + +Since `sort` is a newly implemented feature, a new parser `SortCommandParser`. Similar to its `list` counterpart, `SortCommandParser` will handle the creation of the 3 kinds of sort commands. Similar to above, the `SortCommandParser` will also handle the parsing of the `SearchType` and `Ordering` parameters. Now the `parse()` method can return any of the 3 sort commands. + +To handle the actual sorting, the `SortCommand` will call `Model#sortPersonListByName`/ `Model#sortCompanyListByName`/ `Model#sortEventListByDate` to sort the entries. Each respective call of sort methods in the model calls the same respective method in addressbook. + +Please take note that the `SortCommand` does not just sort the displayed list (`FilteredList`), it also sorts the actual stored list (`UniqueEntryList`). This is to ensure that the order of the list persists even after the user has sorted the list (i.e. calling a `find` or `list` command). + +#### Common Implementation +Note that we are going to use XYZ as a placeholder of either Company, Event, or Person for this section. + +For the `sortXYZ` command: (where `XYZ` is `person`, `company`, or `event`) +1. The user executes `sortXYZ o/descending`. +2. This command is parsed to check if the given optional parameters are there and valid (`o/ORDERING` and `s/SEARCH_TYPE`). If not, a `ParseException` is thrown. In this case, the `Ordering` parameter is set to `DESCENDING` (since `o/descending` is specified, otherwise set to `ASCENDING`) and the `SearchType` parameter is set to `UNARCHIVED` (default value of the optional parameter). +3. Otherwise, the created `SortXYZCommand` object will execute `Model#sortPersonListByName`/ `Model#sortCompanyListByName`/ `Model#sortEventListByDate` depending on `XYZ`. These methods take 2 parameters: the first is the `Predicate` and the second is the `Ordering`. `Predicate` is generated by the command through the `SearchType` parameter. +4. The model will then call the respective sort method in the address book (i.e. `AddressBook#sortPersonListByName`/ `AddressBook#sortCompanyListByName`/ `AddressBook#sortEventListByDate`). These methods in address book requires 1 parameter, which is the `Comparator` object to be used for sorting. The Comparator needed is already predefined in the model. +5. The address book will then call `sort(Comparator)` in the respective `UniqueEntryList`. +6. Finally, the `UniqueEntryList` will sort the entries according to the `Comparator` object passed in. +7. Finally, moving to the model again, the `Model#showXYZList(predicate)` method is called to display the list. The `predicate` is generated by the command through the `SearchType` parameter. +8. The `CommandResult` of the `sortXYZ` command is returned. + +A similar process is performed with the `unarchive` command, but `Entry#setArchived()` is ultimately passed `false` instead of `true`. + +### Adding Feature + +#### Design + +Adding an Entry whether it is Company, Person, or Event is essential for InternBuddy. In particular, it is one of the +most important features to make InternBuddy working. However, notice that each entry has different attributes which +can be tricky to implement. + +The command designs for each type of entries must be similar to make sure that the code is united and coherent. In particular, +although the implementation of `addc`, `addp`, and `adde` commands are similar, it is necessary to divide them out to their own classes. + +While the design of each `add` command is inspired from AB3, there are quite some changes to the implementation as `Event`, `Company`, +and `Person` have different attributes. In particular, there are now 3 `UniqueEntryList` for each `Entry`. This is to make sure that the three different `Entry` +does not mix with each other when displaying in `UI`. + + +#### Common Implementation +Note that we are going to use XYZ as a placeholder of either Company, Event, or Person for this section. + +The Activity Diagram below summarizes what happens when the user enters the add command + + + +For the `addXYZ` command: +1. The user executes `addXYZ` followed by `XYZ` parameters (along with their tags). You can look at our UG to see the parameters. +2. This command is parsed by `AddXYZCommandParser` to check if the given parameters are valid. If not, a `ParseException` is thrown. +3. Otherwise, an `XYZ` object is created and `AddXYZCommand` object will be created accordingly. +4. Next, `AddXYZCommand` will check whether the added `XYZ` object exists in the address book by using `Model#hasEntry()`. + if the added `XYZ` object is a duplicate, then `CommandException` will be thrown. +5. Otherwise, the created `AddXYZCommand` object will call `Model#addXYZ()` to add `XYZ` object to the model. + 1. Next, the model will call `AddressBook#addXYZ()` + 2. Note that in the address book, there is a `UniqueEntryList` which hold all the companies in the address book. + The added `XYZ` object will be added to the list in this function. + 3. Finally, the model will call `updateFilteredXYZList()` to set the display list to be the `XYZ` list. +6. The `CommandResult` of the `XYZ` command is returned. + +Here is the Sequence Diagram for the implementation to understand it better. The Sequence Diagram will be a simplified version +of the actual implementation to show the important sections. +![AddXYZSequenceDiagram](images/AddXYZSequenceDiagram.png) + +In the diagram, `addXYZexample` is just a placeholder for user input. You can look at the UG for sample user input for different +add commands. + +#### Specific Implementation + +1. When adding a company, InternBuddy has to make sure that no other company of the same name has been added. This is to +prevent users from adding multiple redundant duplicates of companies, which is also one of our design decision to improve +user experience. + 1. `check(xyz)` in the diagram will contain `hasCompany(xyz)` + +![AddCompanySequenceDiagram1](images/AddCompanySequenceDiagram1.png) + +2. When adding a person, InternBuddy has to make sure that no other person of the same name has been added. This is to +prevent users from adding multiple redundant duplicates of companies, which is also one of our design decision to improve +user experience. + 1. `check(xyz)` in the diagram will contain `hasPerson(xyz)` and `hasCompany(xyz.getCompanyName)` + +![AddPersonSequenceDiagram1](images/AddPersonSequenceDiagram1.png) + +3. Finally, when adding an event, InternBuddy has to make sure that no other event has the same combination of (name, companyName, date, and time). +This is because we notice that multiple events with the same name should be valid as event's names are more general. Therefore, we consider +more attributes when judging whether two events are the same entry. + 1. `check(xyz)` in the diagram will contain `hasEvent(xyz)` and `hasEvent(xyz.getCompanyName)` + +![AddEventSequenceDiagram1](images/AddEventSequenceDiagram1.png) + +### Finding Feature + +#### Design +This feature allows the user to display selected `Entry` in the address book. It is facilitated by `ModelManager`. This acts as a way for user to +filter the entries by their attributes. + +While the design of each `find` command is inspired from AB3, there are quite some changes to the implementation as `Event`, `Company`, +and `Person` have different attributes. As mentioned, there are now 3 `UniqueEntryList` for each `Entry`. Each command will look at different +`UniqueEntryList` accordingly. + +To understand how each `find` commands work in depth. Look at `CompanyContainsKeywordsPredicate`, `PersonContainsKeywordsPredicate`, and `EventContainsKeywordsPredicate` classes +which are the main logic when filtering each `Entry`. + +The Activity Diagram below summarizes what happens when the user enters the add command + + +#### Common Implementation +Note that we are going to use XYZ as a placeholder of either Company, Event, or Person for this section. + +For the `findXYZ` command: +1. The user executes `findXYZ` followed by `XYZ` parameters (along with their tags). You can look at the parameters in our UG. +2. This command is parsed by `FindXYZCommandParser` to check if the given parameters are valid. If not, a `ParseException` is thrown. +3. Otherwise, `XYZContainsKeywordsPredicate` object will be created. Note that `XYZContainsKeywordsPredicate` is the class responsible to test + whether a particular `XYZ` object fits the queried entry. With this predicate, `FindXYZCommand` object will be created. +4. Next, `FindXYZCommand` will call `Model#showXYZList(predicate)`. + 1. The model will update the displayed list to be the `XYZ` list and choose only the `XYZ` objects that suits the query + using `XYZContainsKeywordsPredicat#test()'. +6. The `CommandResult` of the `XYZ` command is returned. -_{Explain here how the data archiving feature will be implemented}_ +Here is the Sequence Diagram for the implementation to understand it better. +![FindXYZSequenceDiagram](images/FindXYZSequenceDiagram.png) +In the diagram, `FindXYZexample` is just a placeholder for user input. You can look at the UG for sample user input for different +find commands. + +### Editing Feature + +The design and implementation of `edit` commands are similar to `find` commands and their sequence diagrams differ minimally. +For developers, you can trace through the code similarly with the `find` commands. + +### List Feature + +#### Design +This feature allows the user to display unarchived, archived, or all the `Entry` in the address book. It is facilitated by `ModelManager`. This acts as a way for user to display entries in the most general way (respective to the desired entry type). + +As entries can either be archived or unarchived, the parameter `SearchType` can be passed to the `list` command to indicate which entries to display. + +#### Common Implementation +Note that we are going to use XYZ as a placeholder of either Company, Event, or Person for this section. + +For the `listXYZ` command: +1. The user executes `listXYZ` followed by `SearchType` parameters. +2. This command is parsed by `ListXYZCommandParser` to check if the given parameters are valid. If not, a `ParseException` is thrown. +3. Otherwise, `ListXYZCommand` object will be created. +4. Next, `ListXYZCommand` will call `Model#showXYZList(Predicate)` (`Predicate` is generated by `ListXYZCommand` through `SearchType`). +5. The model will update the displayed list to be the `XYZ` list and choose only the `XYZ` objects that suits the search type (unarchived/ archived/ all) using `SearchType`. +6. The `CommandResult` of the `listXYZ` command is returned.= -------------------------------------------------------------------------------------------------------------------- @@ -257,42 +505,143 @@ _{Explain here how the data archiving feature will be implemented}_ **Target user profile**: -* has a need to manage a significant number of contacts -* prefer desktop apps over other types -* can type fast -* prefers typing to mouse interactions -* is reasonably comfortable using CLI apps - -**Value proposition**: manage contacts faster than a typical mouse/GUI driven app +* University student who is looking for internships / full time jobs + * Preferrably university student from School of Computing +* Has a need to manage a significant number of companies, their events, and their contact people during job seeking +* Prefer desktop apps over other types +* Can type fast +* Prefers typing to mouse interactions +* Is reasonably comfortable using CLI apps +**Value proposition**: manage companies, their events, and their contact people faster than a typical mouse/GUI driven app. +Furthermore, `InternBuddy` allows users to effectively combine multiple managing application into one. ### User stories Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` -| Priority | As a …​ | I want to …​ | So that I can…​ | -| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- | -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | +| Priority | As a …​ | I want to …​ | So that I can…​ | +|----------|------------------------------------------------------------|--------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------| +| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | +| `* * *` | user | add companies | keep track of all of my companies | +| `* * *` | user | add events related to a company | keep track of all of a company’s events | +| `* * *` | user | add contact people relared to a company | easily look up their contact details | +| `* * *` | user | delete companies | remove companies that I am no longer considering | +| `* * *` | user | delete events | remove events that have passed or been canceled | +| `* * *` | user | delete contact people | remove people who are no longer related to companies I'm looking at | +| `* * *` | user | view the list of companies | | +| `* * *` | user | view the list of events | | +| `* * *` | user | view the list of contact people | | +| `* * *` | user | save my list | maintain my list across different sessions | +| `* * *` | user considering many companies | find companies by name | locate details of companies without having to go through the whole list | +| `* * *` | user keeping track of many events | find events by name | locate details of events without having to go through the whole list | +| `* * *` | user keeping track of many contact people | find contact people by name | locate their details without having to go through the whole list | +| `* * *` | user keeping track of events from many different companies | find events related to a certain company | locate details of eventts from a certain company without having to go through the whole list | +| `* * *` | user | edit the details of a company | keep the company details accurate and up to date | +| `* * *` | user | edit the details of an event | keep the event details accurate and up to date | +| `* * *` | user | edit the details of a contact person | keep their details accurate and up to date | +| `* * *` | user | receive feedback on whether my command was successful or not | rectify the error in the command if any occurred | +| `* *` | user | add tags to an entry | | +| `* *` | user | edit tags of an entry | | +| `* *` | user | delete tags from an entry | | +| `* *` | user keeping track of many entries | find entries by tags | locate that entry without having to go through the whole list | +| `* *` | user | archive companies | ignore companies I am no longer focusing on but can still view their details if necessary | +| `* *` | user | archive events | ignore events that have passed or been canceled but can still view their details if necessary | +| `* *` | user | archive contact people | ignore contact people no longer connected to a company I’m looking at but can still view their details if necessary | +| `* *` | user | view all events in a certain time frame | see all the events within that time frame without going through the whole list | +| `* *` | user | view all upcoming events within a certain time frame | see all important events that will be coming up soon | +| `* *` | user keeping track of many events | sort events by date | locate an event easily and view their chronological order | +| `* *` | user keeping track of many contact people | sort persons by name | locate a person easily | +| `* *` | user considering many companies | sort companies by name | locate a company easily | +| `* *` | new user | go through a guided tutorial of the app | quickly learn how to use the app | +| `* *` | user | undo the previous command | undo any mistakes I make | +| `* *` | user | redo the previously undone command | redo a command I accidentally undid | +| `* *` | user keeping track of many events | delete all past events | avoid having to delete them one by one | +| `* *` | user keeping track of many events | archive all past events | avoid having to archive them one by one | +| `* *` | user | find companies by all its attributes | locate details of companies without having to go through the whole list | +| `* *` | user | find events by all its attributes | locate details of events without having to go through the whole list | +| `* *` | user | find people by all its attributes | locate details of people without having to go through the whole list | +| `*` | user | choose to save or not save the changes made | avoid having changes I don't want get saved to the file | +| `*` | forgetful user | receive reminders for events happening soon | remember them | +| `*` | user with multiple computers | download the list of contacts | send the list to other computers | +| `*` | user with multiple computers | import the list of contacts | maintain my list between different computers | +| `*` | applicant | send emails directly | send applications without having to open a web browser | +| `*` | applicant | store my resume, cover letter & academic transcript | easily retrieve them when sending an email | +| `*` | calendar user | download my events in ics format | import them into my calendar apps | +| `*` | LinkedIn user | add contact information from a LinkedIn url | easily add LinkedIn contact information to an entry | +| `*` | expert user | remap the commands | use commands I am more comfortable with | +| `*` | expert user | add key bindings/shortcuts | use shortcuts I am comfortable with for efficient usage | +| `*` | expert user | add simple scripts | I can automate common tasks | *{More to be added}* ### Use cases -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +(For all use cases below, the **System** is the `InternBuddy` and the **Actor** is the `user`, unless specified otherwise) + +**Use case: Add a new event for a company** + +**MSS** + +1. User requests to add a new event with details given +2. InternBuddy creates and add a new event to the list of events +3. InternBuddy shows successful feedback to the user +4. InternBuddy displays the updated list of events with the new event +5. User requests to add a new tag to the event with the company name as the tag +6. InternBuddy adds the tag to the event +7. InternBuddy shows successful feedback to the user + + Use case ends. -**Use case: Delete a person** +**Use case: Add a new contact person details** **MSS** -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person +1. User requests to add a new contact person with details given +2. InternBuddy creates a new contact person +3. InternBuddy add the new contact person to the list of contact persons +4. InternBuddy displays the updated list of contact persons with the new contact person +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** +* 5a. User wants to add a company to the contact person + * 5a1. User requests to add a new tag to the contact person with the company name as the tag + * 5a2. InternBuddy adds the tag to the contact person + * 5a3. InternBuddy shows successful feedback to the user + + Use case ends. + +* 5a2. contact person not found + + Use case ends. + +**Use case: Add a new company** + +**MSS** + +1. User requests to add a new company with details given +2. InternBuddy creates a new company +3. InternBuddy assign a tag to the company with the company name as the tag +4. InternBuddy add the new company to the list of companies +5. InternBuddy displays the updated list of companies with the new company +6. InternBuddy shows successful feedback to the user + + Use case ends. + +**Use case: Hide events that have passed or has been cancelled** + +**MSS** + +1. User requests to view list of events +2. InternBuddy shows list of events +3. User requests to archive the event +4. InternBuddy archives and hides the event +5. InternBuddy shows successful feedback to the user +6. InternBuddy update list of events +7. InternBuddy display the updated list of events +8. Repeat steps 3-8 for all events to be hidden Use case ends. @@ -304,24 +653,216 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli * 3a. The given index is invalid. - * 3a1. AddressBook shows an error message. + * 3a1. InternBuddy shows an error feedback to the user Use case resumes at step 2. -*{More to be added}* +**Use case: Edit an existing company** + +**MSS** + +1. User requests to view list of companies +2. InternBuddy shows list of companies +3. User requests to edit a selected company from the list with the given details +4. InternBuddy updates the company's details +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 3a. The selected company is invalid + * 3a1. InternBuddy shows an error feedback to the user + + Use case ends. + +* 3b. The given details is invalid + * 3b1. InternBuddy shows an error feedback to the user + + Use case ends. + +**Use case: Edit an existing person** + +**MSS** + +1. User requests to view list of persons +2. InternBuddy shows list of persons +3. User requests to edit a selected person from the list with the given details +4. InternBuddy updates the person's details +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 3a. The selected person is invalid + * 3a1. InternBuddy shows an error feedback to the user + + Use case ends. + +* 3b. The given details is invalid + * 3b1. InternBuddy shows an error feedback to the user + + Use case ends. + +**Use case: Edit an existing event** + +**MSS** + +1. User requests to view list of events +2. InternBuddy shows list of events +3. User requests to edit a selected event from the list with the given details +4. InternBuddy updates the event details +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 3a. The selected event is invalid + * 3a1. InternBuddy shows an error feedback to the user + + Use case ends. + +* 3b. The given details is invalid + * 3b1. InternBuddy shows an error feedback to the user + + Use case ends. + +**Use case: Delete an existing company** + +**MSS** + +1. User requests to view list of companies +2. InternBuddy shows list of companies +3. User requests to delete a selected company from the list +4. InternBuddy deletes all persons associated with the company +5. InternBuddy deletes the company from the list +6. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 4a. The selected event is invalid + * 4a1. InternBuddy shows an error feedback to the user + + Use case ends. + +**Use case: Delete an existing person** + +**MSS** + +1. User requests to view list of persons +2. InternBuddy shows list of persons +3. User requests to delete a selected person from the list +4. InternBuddy deletes the person from the list +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Use case: Delete an existing event** + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 4a. The selected person is invalid + * 4a1. InternBuddy shows an error feedback to the user + + Use case ends. + +**MSS** + +1. User requests to view list of events +2. InternBuddy shows list of events +3. User requests to delete a selected event from the list +4. InternBuddy deletes the event from the list +5. InternBuddy shows successful feedback to the user + + Use case ends. + +**Extensions** + +* 2a. The list is empty + + Use case ends. + +* 4a. The selected event is invalid + * 4a1. InternBuddy shows an error feedback to the user + + Use case ends. + +**Use case: Locating companies** + +**MSS** + +1. User requests to find a company with a specified attribute +2. InternBuddy shows all the companies that contain the specified attribute +3. InternBuddy shows successful feedback to the user + + Use case ends. + +**Use case: Locating persons** + +**MSS** + +1. User requests to find a person with a specified attribute +2. InternBuddy shows all the persons that contain the specified attribute +3. InternBuddy shows successful feedback to the user + + Use case ends. + +**Use case: Locating companies** + +**MSS** + +1. User requests to find an event with a specified attribute +2. InternBuddy shows all the events that contain the specified attribute +3. InternBuddy shows successful feedback to the user + + Use case ends. -### Non-Functional Requirements -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. *{More to be added}* +### Non-Functional Requirements + +1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. +2. Should be able to hold up to 1000 entries without noticeable lag in performance for typical usage. +3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +4. Entries and their details should be displayed in an intuitive, easy-to-understand manner. +5. The majority of the interactions the user makes with the app should be through the keyboard. +6. Should not use more than 300 MB of RAM memory while in operation. +7. The commands should be intuitive from its name + ### Glossary * **Mainstream OS**: Windows, Linux, Unix, OS-X -* **Private contact detail**: A contact detail that is not meant to be shared with others +* **Entry**: A single entry stored in a list of entries (Contact person/Event/Company) +* **Person**: An entry representing a contact person that consists of a name, company name, phone number, email address, +and a list of tags +* **Event**: An entry representing an event that consists of a name, company name, date, time, location, and a list of tags +* **Company**: An entry representing a company that consists of a name, phone number, email address, and a list of tags -------------------------------------------------------------------------------------------------------------------- @@ -342,36 +883,251 @@ testers are expected to do more *exploratory* testing. 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. -1. Saving window preferences +2. Saving window preferences 1. Resize the window to an optimum size. Move the window to a different location. Close the window. - 1. Re-launch the app by double-clicking the jar file.
+ 2. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained. -1. _{ more test cases …​ }_ +### Listing Entries +
+ :information_source: **Note:** Entry can be either a person, company, or events. In particular, each type of entry has different type of attributes. + 1. Company : Name, Phone, Email, Address, Tags + 2. Person : Name, Phone, Email, CompanyName, Tags + 3. Event : Name, CompanyName, Date, Time, Location, Tags -### Deleting a person +
+1. Listing persons + 1. Test case: `listp`
+ Expected: All unarchived persons are listed. Status message displays "Listed all unarchived persons". + 2. Test case: `listp s/unarchived`
+ Expected: Same as previous. + 3. Test case: `listp s/all` or `listp s/archived`
+ Expected: All or only all archived persons are listed, respectively. Status message displays accordingly. + 4. Test case: `listp s/X` (where x is anything besides `unarchived`, `archived`, or `all`)
+ Expected: No change in the display. Error details shown in the status message. +2. Listing companies or events + 1. Same as previous, but use `listc` or `liste` instead of `listp`, respectively. + +### Deleting an Entry 1. Deleting a person while all persons are being shown + 1. Prerequisites: List all persons using the `listp` command. Multiple persons in the list. + 1. Test case: `delete 1`
+ Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. + 1. Test case: `delete 0`
+ Expected: No person is deleted. Error details shown in the status message. + 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous. - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. +2. Deleting a company or event while all companies/events are being shown, respectively - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. + 1. Similar procedure for testing deleting a person, but use `listc` before deleting companies or `liste` before deleting events instead of `listp`. + 2. Note: when deleting companies, it is expected that all persons/events with a company name that refers to the deleted + company will also be deleted - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. +### Adding an Entry +
+ :information_source: **Note:** Entry can be either a person, company, or events. In particular, each type of entry has different type of attributes. + 1. Company : Name, Phone, Email, Address, Tags + 2. Person : Name, Phone, Email, CompanyName, Tags + 3. Event : Name, CompanyName, Date, Time, Location, Tags - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+
+ +1. Adding a person + 1. Test case: `addp n/N c/C e/example@example.com p/12345678 t/hr` (where `N` is a name not already used by another + person and `C` is a name of an existing company in the address book)
+ Expected: Person is added to the persons list with the details given. Details of the person are also shown in the + status message. + 2. Test case: `addp`
+ Expected: No person is added. Error details shown in the status message. + 3. Any `addp` command which is missing a parameter besides `t/` + Expected: Similar to test 2. + 4. Any `addp` command where the name parameter is a name of an existing person in the address book + Expected: No person is added. Status message should say something to the effect of "Person already exists". + 5. Any `addp` command where the company parameter is a name of a company that doesn't exist + Expected: No person is added. Status message should say something to the effect of "Company name does not refer + to an existing company". + +2. Adding a company/event + 1. Similar to adding a person, but use the `addc` and `adde` commands instead. See User Guide for more details. + +### Archiving an Entry + +1. Archiving an unarchived person + 1. Prerequisites: List all unarchived persons using the `listp` command. Multiple persons in the list. + 2. Test case: `archive 1`
+ Expected: First contact is archived and no longer appears in the list. Details of the archived contact shown in the status message. + 3. Test case: `archive 0`
+ Expected: No person is archived. Error details shown in the status message. + 4. Other incorrect archive commands to try: `archive`, `archive x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous. + +2. Archiving an archived person + 1. Prerequisites: List all archived persons using the `listp s/archived` command. Multiple persons in the list. + 2. Test case: `archive 1`
+ Expected: No change. Status message says that the entry is already archived. + +3. Unarchiving an archived person + 1. Prerequisites: List all archived persons using the `listp s/archived` command. Multiple persons in the list. + 2. Test case: `unarchive 1`
+ Expected: First contact is archived and no longer appears in the list. Details of the unarchived contact shown in the status message. + 3. Test case: `unarchive 0`
+ Expected: No person is archived. Error details shown in the status message. + 4. Other incorrect archive commands to try: `unarchive`, `unarchive x`, `...` (where x is larger than the list size)
Expected: Similar to previous. -1. _{ more test cases …​ }_ +4. Unarchiving an unarchived person + 1. Prerequisites: List all unarchived persons using the `listp` command. Multiple persons in the list. + 2. Test case: `archive 1`
+ Expected: No change. Status message says that the entry is already unarchived. + +5. Archiving all persons + 1. Prerequisites: List all unarchived persons using the `listp s/unarchived` command. Multiple persons in the list. + 2. Test case: `archive_all`
+ Expected: Empty list is displayed. Status message says something to the effect of "archived all entries" + +6. Unarchiving all persons + 1. Prerequisites: List all archived persons using the `listp s/archived` command. Multiple persons in the list. + 2. Test case: `unarchive_all`
+ Expected: Empty list is displayed. Status message says something to the effect of "unarchived all entries" + +7. Unarchiving/archiving companies or events + 1. Follow similar procedure to the above, but use `listc` or `liste` beforehand instead of `listp`. + +### Finding Entries +
+ :information_source: **Note:** Entry can be either a person, company, or events. In particular, each type of entry has different type of attributes. + 1. Company : Name, Phone, Email, Address, Tags + 2. Person : Name, Phone, Email, CompanyName, Tags + 3. Event : Name, CompanyName, Date, Time, Location, Tags + +
+ +1. Finding a person + 1. Finding person by one name + Test case: `findp n/N` (where `N` is a name of an existing person)
+ Expected: All Person with the name containing `N` is shown in the persons list with the details given. + Details of how many people listed are also shown in the + status message. + 2. Finding person by non name parameter + Similar to test case 1, but with different parameter tags. Look at UG for more information. + 3. Finding person by multiple name + Test case: `findp n/N1 N2` (where `N1` and `N2` is names of existing persons
+ Expected: All Person with the name containing `N1` OR `N2` is shown in the persons list with the details given. + Details of how many people listed are also shown in the + status message. + 4. Finding person by no parameters + Test case: `findp`
+ Expected: No person is listed. Error details shown in the status message. + 5. Finding person with invalid parameter + Any `findp` command which is missing a parameter besides `t/` + Expected: Similar to test 4. + 6. Finding non existent person + Any `findp` command where the parameter is of a not any existing person in the address book + Expected: No person is listed. Status message should show a successful command message with no person listed. + +2. Finding a company/event + 1. Similar to finding a person, but use the `findc` and `findp` commands instead. See User Guide for more details. + +### Editing an Entry +
+ :information_source: **Note:** Entry can be either a person, company, or events. In particular, each type of entry has different type of attributes. + 1. Company : Name, Phone, Email, Address, Tags + 2. Person : Name, Phone, Email, CompanyName, Tags + 3. Event : Name, CompanyName, Date, Time, Location, Tags + +
+ +1. Editing a person +
+ :information_source: **Note:** + You need to make sure that the displayed list is the person list before editing person as the edit command relies on using indexes. +
+ 1. Editing a person's name + Test case: `editp 1 n/N` (where 1 is the index of the person to edit and `N` is the new name)
+ Expected: The person's with index 1 will be changed to `N`. + Details of how the person edited is also shown in the status message. + 2. Editing a person by non name parameter + Similar to test case 1, but with different parameter tags. Look at UG for more information. + 3. Editing person without index + Test case: `editp n/N1`
+ Expected: An error message will show index information that you need to follow. No person will be edited. + 4. Editing person by no parameters + Test case: `editp`
+ Expected: No person is edited. Error details shown in the status message. + 5. Editing person with invalid parameter + Any `findp` command which is missing a parameter besides `t/` + Expected: Similar to test 4. + 6. Editing non existent person + Any `findp X n/N` command where X is invalid index (below 1 or above the number of people listed) + Expected: No person is edited. Status message will be an error message + +3. Editing a company/event + 1. Similar to finding a company, but use the `editc` and `editp` commands instead. See User Guide for more details. + +### Sorting entries + +1. Sorting companies + 1. Test case: `sortc`
+ Expected: List of companies is sorted alphabetically. List of companies currently unarchived displayed. Status message displays "Sorted all companies unarchived in ascending order". + + 2. Test case: `sortc o/ascending`
+ Expected: Same as previous. + + 3. Test case: `sortc o/descending`
+ Expected: List of companies is sorted alphabetically in descending order. List of companies currently unarchived displayed. Status message displays "Sorted all companies unarchived in descending order". + + 4. Test case: `sortc o/X` (where X is anything besides `ascending` or `descending`)
+ Expected: No change. Error details shown in status message. + + 5. Test case: `sortc s/archived`
+ Expected: List of companies is sorted alphabetically. List of companies currently archived displayed. Status message displays "Sorted all companies archived in ascending order". + + 6. Test case: `sortc s/all o/descending`
+ Expected: List of companies is sorted alphabetically in descending order. List of companies displayed. Status message displays "Sorted all companies in descending order". +2. Sorting persons or events + 1. Follow similar procedure to the above, but use sortp or sorte beforehand instead of sortc. ### Saving data -1. Dealing with missing/corrupted data files +1. Dealing with corrupted data file + 1. Open `addressbook.json` in the `data/` folder + 2. In the first line, add the letter `a` after the bracket + 3. Save and close the file + 4. Start InternBuddy
+ Expected: All lists are empty. - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ +2. Dealing with missing data file + 1. Delete `addressbook.json` + 2. Start InternBuddy
+ Expected: Sample company list is displayed. Persons and Events list also have sample entries. -1. _{ more test cases …​ }_ +-------------------------------------------------------------------------------------------------------------------- +## **Appendix: Effort** + +**Difficulty Level**: Medium + +**Effort Required**: Around the effort level required for AB3 + +**Challenges Faced**: +* implementing the commands to work for all 3 types of entries +* implementing the commands to work with different attributes of different entries. +* extending and refactoring existing architecture to work for all 3 types of entries +* maintaining OOP design and keeping dependencies and code reuse to a minimum +* adding multiple new features that didn't have an existing framework in AB3 originally, such as Archive and Sorting +* finding bugs and writing automated tests for all the new features +* maintaining the property that all `Event` and `Person` objects must refer to a `Company` object - even through editing and deletion +* updating the UI to give it a new look as well as handle the new entries + +**Achievements of the Project**: +* enhanced the original AB3 project with all new features, such as Archiving and Sorting +* updated AB3 to support `Companies` and `Events` along with the original `Persons`, including updating all existing commands + to handle each type of entry +* added many Quality-of-Life commands to improve use, such as a command to delete all entries in a list and being able + to find entries by attributes other than the name +* upgrading all the commands to more intuitive command +* updating the UI with better colour design to make the application prettier. +* did all of the above while keeping the project OOP, clean, and extendable diff --git a/docs/SettingUp.md b/docs/SettingUp.md index 275445bd551..b0991c7ac7d 100644 --- a/docs/SettingUp.md +++ b/docs/SettingUp.md @@ -45,7 +45,7 @@ If you plan to use Intellij IDEA (highly recommended): 1. **Learn the design** - When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [AddressBook’s architecture](DeveloperGuide.md#architecture). + When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [InternBuddy’s architecture](DeveloperGuide.md#architecture). 1. **Do the tutorials** These tutorials will help you get acquainted with the codebase. diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3716f3ca8a4..06b99e6ef77 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,190 +3,989 @@ layout: page title: User Guide --- -AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps. +## 1. Introduction -* Table of Contents +Hi there! Welcome to the User Guide for InternBuddy! We are here to help guide you on your journey with our application. **Keep on reading to become an InternBuddy Guru!** + +### 1.1. What is InternBuddy? + +InternBuddy is a **desktop application to help computer science students manage their events, companies, and contact people encountered during the internship search.** + +This application is optimized for use via a **Command Line Interface (CLI)** while still having the benefits of a **Graphical User Interface (GUI).** + +If you can type fast, InternBuddy can definitely help you organize your internship search faster than traditional GUI apps. + +### 1.2. Purpose of The User Guide + +The purpose of this User Guide is to assist you in learning and using InternBuddy. Whether you're a new user looking for a place to start or a veteran needing a quick reference, this guide is here to answer your questions. + +
:bulb: **Tip:** +If you have never used InternBuddy before, the [Quick Start](#4-quick-start) section is super useful for you to start! +
+ +### 1.3. InternBuddy Target Audience + +InternBuddy is designed and optimised for **Computer Science Students who are looking to manage their internship**. However, if you are not a Computer Science Student, worry not! Our User Guide +is meant for anyone who wants to try and learn how to use InternBuddy. + +### 1.4. Helping Icons + +Here are some icons that can help us emphasize any important information for you. Do read what it means beforehand! + +| Icon | Meaning | +| -------------------- | ------------------------------------------------------------------------------------------------- | +| :information_source: | This icon indicates important information to be taken note of | +| :bulb: | This icon indicates useful tips for the users | +| :exclamation: | This icon indicates caution for an action the user can take that can have dangerous consequences. | + +## 2. Table of Contents + +- Table of Contents {:toc} --------------------------------------------------------------------------------------------------------------------- -## Quick start +--- + +## 3. Quick start + +If you're interested in using InternBuddy but don't know where to begin, this section will give you a step-by-step walkthrough to get you started! + +1. Ensure you have Java `11` or above installed in your Computer. + + - If you don't have it installed, you can follow [Oracle's JDK installation guide](https://docs.oracle.com/en/java/javase/11/install/installation-guide.pdf) + for your operating system. + - Also ensure that you have selected Java `11` as your default Java version. + - If you are not sure which version of Java that you currently have, you can follow this [Java Manual](https://www.java.com/en/download/help/version_manual.html) + to check. + +2. Download the latest `InternBuddy.jar` from [here](https://github.com/AY2122S2-CS2103T-W14-3/tp/releases/download/v1.4.0/internbuddy.jar). + +3. Copy the file to the folder you want to use as the _home folder_ for InternBuddy. + +4. Double-click the file to start the app. A window similar to the one below should appear in a few seconds. Note how the app contains some sample data.
+ + | ![Opening UI](images/UserGuide/Ui-1.png) | + | :--------------------------------------: | + | InternBuddy app | + +5. Type the command in the command box and press Enter to execute it. e.g. typing `help` and pressing Enter will open the help window.
+ Some example commands you can try: + + - `listc` : Lists all companies. + + - `addc n/DeeBee p/98765432 e/dbs@example.com a/14 Jurong Street #01-01` : Adds a company named `DeeBee` to the list of companies. + + - `delete 3` : Deletes the 3rd contact shown in the currently displayed list. + + - `delete_all` : Deletes all entries in the currently displayed list. + + - `exit` : Exits the app. + +
:bulb: **Tip:** + If you currently do not understand the commands above, don't worry! This is section is for you to install and get the feel for the application. +
+ +6. If this is your first time reading our user guide, you can refer to the [Overview](#4-overview-of-internbuddy) section + to learn more about the app, or to the [Features Guide](#5-features-guide) section to better understand the [Features Details](#6-features-details) + section of the app. + +--- + +## 4. Overview of InternBuddy + +**InternBuddy** is specially designed for Computer Science Students who are searching for internships. With **InternBuddy**, there is no need +for you to juggle between multiple apps just to manage your multiple internship applications. + +This app values your +**Time** and **Experience** by placing efficiency as one of its core principles. Let InternBuddy help you manage your +internship application details so you can focus on acing your assessments and interviews! + +This section will go into detail as to how the application works. + +### 4.1. User Interface + +**In short, what you see!** + +When you first open InternBuddy, InternBuddy will present you with: + +| ![Annotated user interface](images/UserGuide/Ui-annotated.png) | +| :------------------------------------------------------------: | +| Main components of InternBuddy | + +As you can see in the image above, there are 3 main components of InternBuddy: + +1. Entry List + + InternBuddy's **Entry List** is a scrollable list containing entries which is explained in [Structure of InternBuddy](#42-structure-of-internbuddy). At the top of the Entry List, you can see the type of entry that is currently displayed. + +2. Dialog Box + + **The Dialog Box** is where InternBuddy gives you the details of the commands that you have entered. More on this in [Dialog Box](#432-dialog-box) + +3. Command Box + This is where you can input commands to InternBuddy by typing them and then pressing enter. This is the main way of [interacting with **InternBuddy**](#43-interacting-with-the-app). +
:bulb: **Tip:** + After you type and enter any commands to InternBuddy, the details of the command will be given in The Dialog Box. + From here, you can know whether your command is successfully entered or not! +
+ +### 4.2. Structure of InternBuddy + +Because internships and job seeking is InternBuddy's main focus, the app supports 3 kinds of entries: + +- **Company**: Represents a company that you are applying for, or will be applying for. +- **Person**: Represents a contact person of a company. The contact person may have a specific role such as being an HR recruiter. +- **Event**: Represents an event of a company. An event can be an online assessment, an interview, a job fair, etc. + +With that, InternBuddy stores 3 entry lists, one for each entry type: + +- **[Company List](#421-company-list)** +- **[Person List](#422-person-list)** +- **[Event List](#423-event-list)** + +The app will only display one of these lists at any time, as shown in the screenshots of each of these lists. Lists cannot +have duplicate entries; the criteria for what counts as a duplicate entry will be listed in the sections below. + +Each of these 3 entry types have different attributes attached to them. Let's dive in to understand what attributes each +entry type can store. + +#### 4.2.1. Company List + +| ![Company List](images/UserGuide/Ui-2.png) | +| :----------------------------------------: | +| Entry list showing companies | + +A **Company** entry has: + +- A _name_ +- An _email address_ +- A _phone number_ +- A _real-life address_ +- Zero or more _tags_ associated with them + +**Two Company entries are considered duplicates of each other if they have the same name.** + +#### 4.2.2. Person List + +| ![Person List](images/UserGuide/Ui-3.png) | +| :---------------------------------------: | +| Entry list showing contacts | + +A **Person** entry has: + +- A _name_ +- The _name_ of the Company the Person is associated with +- An _email address_ +- A _phone number_ +- Zero or more _tags_ associated with them + +**Two Person entries are considered duplicates of each other if they have the same name.** + +#### 4.2.3. Event List + +| ![Event List](images/UserGuide/Ui-4.png) | +| :--------------------------------------: | +| Entry list showing events | + +Finally, an **Event** entry has: + +- A _name_ +- The _name_ of the Company the Event is associated with +- A _date_ +- A _time_ +- A _location_ +- Zero or more _tags_ associated with them + +**Two Event entries are considered duplicates of each other if they have the same name, date, time, and company name.** + +### 4.3. Interacting with the app + +Since InternBuddy is designed to be used via a Command Line Interface (CLI), you will be interacting with the app mostly through the Command Box by **typing commands in the Command Box** and **hitting the Enter key** afterwards.
+ +| ![Command Box](images/UserGuide/Command-Box.png) | +| :----------------------------------------------: | +| InternBuddy's Command Box | + +#### 4.3.1. Commands -1. Ensure you have Java `11` or above installed in your Computer. +Commands are sequences of words that follows a predetermined [format](#51-command-formats) that informs InternBuddy what to do. -1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases). +InternBuddy's commands follows a simple classification system for all 3 lists. There are 5 types of commands: -1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook. +- **Adding entries** + - [`addc`](#621-adding-a-company-addc): Adds a company to the list of companies. + - [`addp`](#622-adding-a-person-addp): Adds a person to the list of persons. + - [`adde`](#623-adding-an-event-adde): Adds an event to the list of events. +- **Listing/Viewing entries** + - [`listc`](#631-listing-all-companies--listc): Lists all companies. + - [`listp`](#632-listing-all-persons--listp): Lists all persons. + - [`liste`](#633-listing-all-events--liste): Lists all events. +- **Sorting entries** + - [`sortc`](#661-sorting-companies-by-name-sortc): Sorts companies by name. + - [`sortp`](#662-sorting-people-by-name-sortp): Sorts persons by name. + - [`sorte`](#663-sorting-events-by-date-sorte): Sorts events by date. +- **Editing entries** + - [`editc`](#641-editing-a-company--editc): Edits a company. + - [`editp`](#642-editing-a-person--editp): Edits a person. + - [`edite`](#643-editing-an-event--edite): Edits an event. +- **Archiving entries** + - [`archive`](#671-archiving-an-entry-archive): Archives an entry. + - [`archive_all`](#672-archiving-all-entries-in-display-archive_all): Archives all entries in the display. + - [`unarchive`](#673-unarchiving-an-entry-unarchive): Unarchives an entry. + - [`unarchive_all`](#674-unarchiving-all-entries-in-display-unarchive_all): Unarchives all entries in the display. +- **Deleting entries** + - [`delete`](#681-deleting-an-entry--delete): Deletes an entry. + - [`delete_all`](#682-deleting-all-entries-in-display--delete_all): Deletes all currently displayed entries. + - [`clear`](#683-clearing-all-entries--clear): Deletes all entries. +- **Finding/Locating entries** + - [`findc`](#651-locating-companies-findc): Finds a company. + - [`findp`](#652-locating-people-findp): Finds a person. + - [`finde`](#653-locating-events-finde): Finds an event. +- **Miscellaneous** + - [`help`](#611-viewing-help--help): Open the help window which contains the link to this User Guide. + - [`clear`](#683-clearing-all-entries--clear): Delete all entries from all lists. + - [`exit`](#69-exiting-the-program--exit): Exit and close the application. -1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png) +You can try clicking on the commands above to see how to use them in further details. However, we would suggest you to +read the [Features Guide](#5-features-guide) section first to have a smoother +experience reading our [Features Details](#6-features-details) section :smile:. -1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
- Some example commands you can try: +#### 4.3.2. Dialog Box - * **`list`** : Lists all contacts. +For those of you not familiar with what a dialog box is, a dialog box is a box that shows when you execute a command. It is a box that contains a message. The message is basically a feedback from InternBuddy to you. InternBuddy will show you a dialog box when you execute a command. - * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book. +If the command you tried to execute is **invalid** for whatever reason, an **error message** will be shown and the command you typed will remain. An example of this is shown below. - * **`delete`**`3` : Deletes the 3rd contact shown in the current list. +| ![invalid commmand message](images/InvalidCommandMessageExample.png) | +| :------------------------------------------------------------------: | +| Invalid command result | - * **`clear`** : Deletes all contacts. +Otherwise, if the command is **valid**, a **success message** will be shown and the command will be executed. The command box will also be cleared. - * **`exit`** : Exits the app. +| ![successful command](images/SuccessfulCommandExample.png) | +| :--------------------------------------------------------: | +| Valid command result | -1. Refer to the [Features](#features) below for details of each command. +### 4.4. Archive --------------------------------------------------------------------------------------------------------------------- +InternBuddy supports archiving entries. When an entry is archived, it will be **"hidden"** from the entry list unless the user +specifically chooses to display them. However, it will still technically +exist in the entry list, and the entry can be unarchived when needed. For example, an Event or Person can still store the company name of an archived Company. -## Features +The below screenshot shows what archived entries look like. Notice the `ARCHIVED` tag? + +| ![archived entry](images/ArchivedEntryExample.png) | +| :------------------------------------------------: | +| Contacts list showing archived entries | + +--- + +## 5. Features Guide + +This section will help you navigate and understand the [Features Details](#6-features-details) section of the guide. +This way, you can easily use it to answer any question you have regarding the app's features. + +### 5.1. Command Formats + +With a simple command standards, we tried to make the commands as intuitive as possible. To make sure that you can read the commands without any confusion, here are the formats we use in the guide.
**:information_source: Notes about the command format:**
-* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. +- Words in `UPPER_CASE` are the parameters to be supplied by the user.
+ e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. -* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. +- Items in square brackets are optional.
+ e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. -* Items with `…`​ after them can be used multiple times including zero times.
- e.g. `[t/TAG]…​` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. +- Items with `…`​ after them can be used multiple times including zero times.
+ e.g. `[t/TAG]…​` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. -* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. +- Parameters can be in any order.
+ e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. -* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken. +- If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
+ e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken. -* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
- e.g. if the command specifies `help 123`, it will be interpreted as `help`. +- Extraneous parameters for commands that do not take in parameters (such as `help`, `exit` and `clear`) will be ignored.
+ e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-### Viewing help : `help` +### 5.2. Command Parameters -Shows a message explaning how to access the help page. +For reference, here is the list of parameters along with the commands that utilize this parameters. We also add a short description of the parameters so you can understand it better :) . -![help message](images/helpMessage.png) +| Parameter | Commands | Description | +| --------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| `n/` | `addc`, `addp`, `adde`, `editc`, `editp`, `edite`, `findc`, `findp`, `finde` | Name of the entry | +| `c/` | `adde`, `addp`, `edite`, `editp`, `findp`, `finde` | Name of the company a person or event related to | +| `p/` | `addc`, `addp`, `editc`, `editp` | Phone number of the person or company | +| `e/` | `addc`, `addp`, `editc`, `editp` | Email address of the person or company | +| `a/` | `addc`, `editc` | Address of the company | +| `l/` | `adde`, `edite`, `finde` | Location of the event | +| `d/` | `adde`, `edite` | Date of the event | +| `sd/` | `finde` | Start date used to search for events happening at the start date and afterward (inclusive) | +| `ed/` | `finde` | End date used to search for events happening at the end date and previously (inclusive) | +| `ti/` | `adde`, `edite`, `finde` | Time of the event | +| `s/` | `listc`, `listp`, `liste`, `findc`, `findp`, `finde`, `sortc`, `sortp`, `sorte` | Search type used to filter archived, unarchived, or all entries | +| `o/` | `sortc`, `sortp`, `sorte` | Orderings used to sort the entries in ascending or descending order | +| `t/` | `addc`, `addp`, `adde`, `editc`, `editp`, `edite`, `findc`, `findp`, `finde` | Tags tagged to an entry | -Format: `help` +### 5.3. Command Parameter Restrictions +Some parameters have special restrictions on what counts as a valid input. These restrictions are listed below. +If a parameter is not listed below, it has no special restrictions. -### Adding a person: `add` +
+**:information_source: Note:** +An empty input or an input consisting only of spaces is invalid for every parameter +
-Adds a person to the address book. +- `n/NAME` - Must only consist of letters or numbers +- `c/COMPANY_NAME` - Must refer to the name of an existing Company in the app +- `p/PHONE` - Must contain only numbers and be at least 3 digits long +- `e/EMAIL` - Must be of the form `local-part@domain`. The `domain` must contain at least one period. +- `d/DATE`, `sd/START_DATE`, and `ed/END_DATE` - Must be of one of the following forms: + - `YYYY-MM-DD` e.g. `2022-01-22` (It must still be a valid date) + - `today` (InternBuddy will interpret this as today's date) + - `today DAY` e.g. `today 3` (`DAY` should be an integer. InternBuddy will interpret this as `DAY` days after today's date) +- `ti/TIME` - Must be in `HH:MM` format and be a valid time e.g. `22:40` +- `s/SEACH_TYPE` - Must be one of `unarchived`, `archived`, or `all` + - If no `s/` parameter is given, InternBuddy will default to `unarchived`. +- `o/ORDERING` - Must be either `ascending` or `descending` + - If no `o/` parameter is given, InternBuddy will default to `ascending`. -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` +
:bulb: **Tip:** +For the `DATE`, `START_DATE`, and `END_DATE` parameters, the keyword `today` is case-insensitive. +
+ +If a parameter violates these restrictions, an error message will appear +in the Dialog Box. An example of this is shown below. + +| ![parameter error](images/ParameterErrorExample.png) | +| :------------------------------------------------------: | +| Error message in the dialog box after an invalid command | + +### 5.4. That's all for the Basic! + +And that's all there is to it! Now that you have a basic understanding of the commands, You can now get started on +learning all the important [commands](#6-features-details) you can use to organize your InternBuddy lists. If you have any trouble, +do refer back to the user guide and the [FAQ](#8-faq) section. Good luck! :confetti_ball: :confetti_ball: :confetti_ball: + +--- + +## 6. Features Details + +Our InternBuddy has a number of features that you can use to organize your InternBuddy lists. These features follow a certain command format. If you haven't read it, please refer to the [User Guide Icons](#14-helping-icons) and [Command Formats](#51-command-formats) section first. If you are still confused, please refer to the [FAQ](#8-faq) section. Otherwise, you can start using the features listed below. :smile:
:bulb: **Tip:** -A person can have any number of tags (including 0) +Read the Glossary section to find some uncommon or niche words in the user guide.
+### 6.1. Getting help + +#### 6.1.1. Viewing help : `help` + +Shows a message explaining how to access the help page. + +| ![help message](images/helpMessage.png) | +| :-------------------------------------: | +| Help message window | + +Format: + +``` +help +``` + +### 6.2. Adding entries + +
:bulb: **Tip:** +Adding an entry may fail and display an error message if the entry already exists. You can try to do `listc s/all`/`listp s/all`/`liste s/all` +to see all the entries (archived and unarchived) in the display. This way, you can check if the entry already exists. +
+ +#### 6.2.1. Adding a company: `addc` + +Adds a company to the list of companies. + +Format: + +``` +addc n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​ +``` + +
:bulb: **Tip:** +Entries can have any number of tags (including 0) +
+ +Examples: + +- `addc n/Shopee p/96113432 e/shopee@gmail.com a/14 Jurong Street #01-01` +- `addc n/DBS t/bank e/dbs@protonmail.com p/1234567 a/31 Race Card Road #02-03 t/financial` +- `addc n/Company e/company@gmail.com p/91142678 a/ 123 Race Course Road` (see screenshot below) + +| ![Add Company Example](images/AddCompanyExample.png) | +| :--------------------------------------------------: | +| Successfully adding a company | + +#### 6.2.2. Adding a person: `addp` + +Adds a person to the list of contact people. + +Format: + +``` +addp n/NAME c/COMPANY_NAME p/PHONE_NUMBER e/EMAIL [t/TAG]…​ +``` + Examples: -* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` -### Listing all persons : `list` +- `addp n/John Doe c/Shopee p/98765432 e/johnd@example.com` +- `addp n/Betsy Crowe c/DBS t/friend e/bcrowe@example.com p/1234567 t/hr` (see screenshot below) + +| ![Add Person Example](images/AddPersonExample.png) | +| :------------------------------------------------: | +| Successfully adding a person | + +#### 6.2.3. Adding an event: `adde` -Shows a list of all persons in the address book. +Adds an event to the list of events. -Format: `list` +Format: -### Editing a person : `edit` +``` +adde n/NAME c/COMPANY_NAME d/DATE ti/TIME l/LOCATION [t/TAG]…​ +``` + +Examples: -Edits an existing person in the address book. +- `adde n/Interview c/DBS d/2022-04-02 ti/14:00 l/Zoom` (see screenshot below) +- `adde n/Career Talk ti/10:00 d/2022-03-19 c/Sony t/important l/22 Clementi Rd` +- `adde n/Practical Test c/ABC d/today ti/15:00 l/Zoom` -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…​` +| ![Add Event Example](images/AddEventExample.png) | +| :----------------------------------------------: | +| Successfully adding an event | -* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …​ -* At least one of the optional fields must be provided. -* Existing values will be updated to the input values. -* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative. -* You can remove all the person’s tags by typing `t/` without - specifying any tags after it. +### 6.3. Listing entries + +#### 6.3.1. Listing all companies : `listc` + +Shows a list of all companies in the list of companies. + +Format: + +``` +listc [s/SEARCH_TYPE] +``` Examples: -* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. -* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. -### Locating persons by name: `find` +- `listc` (defaults to `s/unarchived`) displays all unarchived companies (see screenshot below). +- `listc s/archived` displays all archived companies. + +| ![Company List](images/UserGuide/Ui-2.png) | +| :----------------------------------------: | +| Listing all unarchived companies | -Finds persons whose names contain any of the given keywords. +#### 6.3.2. Listing all persons : `listp` -Format: `find KEYWORD [MORE_KEYWORDS]` +Shows a list of all people in the list of contact people. -* The search is case-insensitive. e.g `hans` will match `Hans` -* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -* Only the name is searched. -* Only full words will be matched e.g. `Han` will not match `Hans` -* Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` +Format: + +``` +listp [s/SEARCH_TYPE] +``` Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png) -### Deleting a person : `delete` +- `listp` (defaults to `s/unarchived`) displays all unarchived people (see screenshot below). +- `listp s/archived` displays all archived people. + +| ![Persons List](images/UserGuide/Ui-3.png) | +| :----------------------------------------: | +| Listing all unarchived people | -Deletes the specified person from the address book. +#### 6.3.3. Listing all events : `liste` -Format: `delete INDEX` +Shows a list of all events in the list of events. -* Deletes the person at the specified `INDEX`. -* The index refers to the index number shown in the displayed person list. -* The index **must be a positive integer** 1, 2, 3, …​ +Format: + +``` +liste [s/SEARCH_TYPE] +``` Examples: -* `list` followed by `delete 2` deletes the 2nd person in the address book. -* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. -### Clearing all entries : `clear` +- `liste` (defaults to `s/unarchived`) displays all unarchived events (see screenshot below). +- `liste s/archived` displays all archived events. + +| ![Events List](images/UserGuide/Ui-4.png) | +| :---------------------------------------: | +| Listing all unarchived events | -Clears all entries from the address book. +### 6.4. Editing entries + +
+ +**:information_source: Notes about the Edit Commands:**
+ +- Each edit command identifies the entry to edit based on the `INDEX`. +- The index refers to the index number shown in the appropriately displayed list. For example, for the `editp` command, the index refers to the index in the displayed person list. +- The index **must be a positive integer** 1, 2, 3,... +- At least one parameter aside from `INDEX` must be provided. +- For the parameters not included in the edit command, the values stored for those parameters will remain the same. +- When editing tags, the existing tags of the entry will be removed i.e adding of tags is not cumulative. +- **When using the command `editc`, `editp`, or `edite`, the command will not work unless the respective list of entries is displayed (i.e. `editc` works after `listc` or `findc` or `sortc` command)**. + +
+ +
:bulb: **Tip:** +You can remove all of an entry’s tags by typing `t/` without specifying any tags after it. +
+ +#### 6.4.1. Editing a company : `editc` + +Edits an existing company in the list of companies. + +Format: + +``` +editc INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]… +``` + +
:exclamation: **Caution:** +If the name of a Company is edited, all Events and Persons referring to that Company will also +update the company name they have stored. +
+ +Examples: -Format: `clear` +- `editc 1 p/91234567 e/company@example.com` edits the phone number and email address of the 1st company to be `91234567` and `company@example.com` respectively (see screenshot below). +- `editc 2 n/Shoppee t/` edits the name of the 2nd company to be `Shoppee` and clears all existing tags. -### Exiting the program : `exit` +| ![Editing a company](images/EditCompanyExample.png) | +| :-------------------------------------------------: | +| Successfully editing a company | + +#### 6.4.2. Editing a person : `editp` + +Edits an existing person in the list of contact people. + +Format: + +``` +editp INDEX [n/NAME] [c/COMPANY_NAME] [p/PHONE] [e/EMAIL] [t/TAG]…​ +``` + +Examples: + +- `editp 1 p/91234567 e/johndoe@example.com` edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively (see screenshot below). +- `editp 2 n/Betsy Crower t/` edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. + +| ![Editing a person](images/EditPersonExample.png) | +| :-----------------------------------------------: | +| Successfully editing a person | + +#### 6.4.3. Editing an event : `edite` + +Edits an existing event in the list of events. + +Format: + +``` +edite INDEX [n/NAME] [c/COMPANY_NAME] [d/DATE] [ti/TIME] [l/LOCATION] [t/TAG]… +``` + +Examples: + +- `edite 1 d/2021-12-21 l/Zoom` edits the date and location of the 1st event to be `2021-12-21` and `Zoom` respectively. +- `edite 2 n/Resume Screening t/` edits the name of the 2nd event to be `Resume Screening` and clears all existing tags. + +| ![Editing an event](images/EditEventExample.png) | +| :----------------------------------------------: | +| Successfully editing an event | + +### 6.5. Locating entries + +- The search is case-insensitive. e.g `hans` will match `Hans` +- The order of the keywords does not matter. e.g. `findp n/Hans Bo` is the same as `findp n/Bo Hans` +- Only full words will be matched e.g. `findp n/Han` will not match a Person with the name `Hans` +- Entries matching at least one keyword will be returned (i.e. `OR` search). + e.g. `findp n/Hans Bo` will return `Hans Gruber`, `Bo Yang` +- At least one of the parameters must be provided. + +#### 6.5.1. Locating companies: `findc` + +Finds all companies which have a name and tags that contain any of the given keywords and displays them as a list +with index numbers. + +Format: + +``` +findc [n/NAME] [s/SEARCH_TYPE] [t/TAG]… +``` + +Examples: + +- `findc n/sgshop dbsss` returns `SGShop` and `DBSSS` (see screenshot below) +- `findc n/Shopee` returns `Shopee` and `Shopee Express` +- `findc n/abc google` returns `Google`, `ABC Pte`
+ +| ![Finding a company](images/FindCompanyExample.png) | +| :-------------------------------------------------: | +| Finding a company named sgshop and dbss | + +#### 6.5.2. Locating people: `findp` + +Finds all persons whose name, company name, and tags contain any of the given keywords and displays them as a list +with index numbers. + +Format: + +``` +findp [n/NAME] [c/COMPANY_NAME] [s/SEARCH_TYPE] [t/TAG]… +``` + +Examples: + +- `findp n/John` returns `john` and `John Doe` +- `findp n/alex david` returns `Alex Yeoh`, `David Li` (see screenshot below)
+ +| ![result for 'find alex david'](images/findAlexDavidResult.png) | +| :-------------------------------------------------------------: | +| Finding alex and david in the contact list | + +#### 6.5.3. Locating events: `finde` + +Finds all events whose name, company, start date, end date, time, location and tags contains the specified keywords +and displays them as a list with index numbers. + +
:information_source: **Note:** +START_DATE and END_DATE will find events from the START_DATE to the END DATE **inclusively**. +
+ +Format: + +``` +finde [n/NAME] [c/COMPANY_NAME] [sd/START_DATE] [ed/END_DATE] [ti/TIME] [l/LOCATION] [s/SEARCH_TYPE] [t/TAG]… +``` + +Examples: + +- `finde n/online` returns `online interview` and `online assessment` +- `finde s/all n/online` returns `online interview`, `online assessment`, `online assessment` +- `finde s/archived n/test` returns `software test`, `practical test`
(given both events have been archived) +- `finde sd/Today ed/2022-05-21` returns all events where the date is between today and 2022-05-21. + +| ![Find an Event](images/FindEventExample.png) | +| :----------------------------------------------------------: | +| Finding all events between Today (2022-04-15) and 2022-05-21 | + +### 6.6. Sorting entries + +
+ +**:information_source: Notes about the Sort Commands:**
+ +- Sort commands will sort the entry list in a certain order and display it +- The entry list that is displayed and sorted depends on the sorting command used +
+ +Below are screenshots of sorting the company list in ascending order (above) and descending order (below). + +| ![Sorting Ascending](images/SortAscendingExample.png) | +| :---------------------------------------------------: | +| Sorting the company list in ascending order | + +| ![Sorting Descending](images/SortDescendingExample.png) | +| :-----------------------------------------------------: | +| Sorting the company list in desceding order | + +#### 6.6.1. Sorting companies by name: `sortc` + +Sorts companies by name. The default is in `ascending` order. To sort in `descending` order, use `sortc o/descending`. + +Format: + +``` +sortc [s/SEARCH_TYPE] [o/ORDERING] +``` + +Examples: + +- `sortc` returns all unarchived companies in ascending order (see screenshot below) +- `sortc o/descending` returns all unarchived companies in descending order +- `sortc s/all o/descending` returns all companies in descending order + +#### 6.6.2. Sorting people by name: `sortp` + +Sorts people by name. The default is in `ascending` order. To sort in `descending` order, use `sortp o/descending`. + +Format: + +``` +sortp [s/SEARCH_TYPE] [o/ORDERING] +``` + +Examples: + +- `sortp` returns all unarchived people in ascending order +- `sortp o/descending` returns all unarchived people in descending order +- `sortp s/all o/descending` returns all people in descending order + +#### 6.6.3. Sorting events by date: `sorte` + +Sorts events by date. The default is in `ascending` order. To sort in `descending` order, use `sorte o/descending`. + +Format: + +``` +sorte [s/SEARCH_TYPE] [o/ORDERING] +``` + +Examples: + +- `sorte` returns all unarchived events in ascending order +- `sorte o/descending` returns all unarchived events in descending order +- `sorte s/all o/descending` returns all events in descending order + +### 6.7. Archiving entries + +
+ +**:information_source: Notes about the Archive Commands:**
+ +- Archived entries will be "hidden" from their entry list unless the user specifically searches for them + (e.g. by using the `s/archived` or `s/all` [parameter](#52-command-parameters)) +- Only unarchived entries can be archived; similarly, only archived entries can be unarchived. + +
+ +#### 6.7.1. Archiving an entry: `archive` + +Archives an entry in the currently displayed list. + +Format: + +``` +archive INDEX +``` + +Examples: + +- `archive 1` archives the 1st entry in the currently displayed list. + +
:bulb: **Tip:** +Use a list, find, or sort command to get all unarchived entries first. That way, you can get the INDEX of the entry +you want to archive. +
+ +| ![Archiving an entry](images/ArchiveEntryExample.png) | +| :----------------------------------------------------------: | +| Archived DBS, the first entry on the previous displayed list | + +#### 6.7.2. Archiving all entries in display: `archive_all` + +Archiving all the entries displayed in the currently displayed list. + +Format: + +``` +archive_all +``` + +| ![Archiving all entries](images/ArchiveAllExample.png) | +| :----------------------------------------------------: | +| Archived all entries on the displayed list | + +#### 6.7.3. Unarchiving an entry: `unarchive` + +Unarchiving an entry will show it in the list of entries. + +Format: + +``` +unarchive INDEX +``` + +| ![Unarchiving an entry](images/UnarchiveEntryExample.png) | +| :-----------------------------------------------------------------: | +| DBS not showing in the archived company list after being unarchived | + +Examples: + +- `unarchive 1` shows the 1st entry in the list of entries. + +
:bulb: **Tip:** +Use a list, find, or sort command to get all archived entries first. That way, you can get the INDEX of the entry +you want to unarchive. +
+ +#### 6.7.4. Unarchiving all entries in display: `unarchive_all` + +Unarchiving all the entries displayed in the currently displayed list. + +Format: + +``` +unarchive_all +``` + +| ![Unarchiving all entry](images/UnarchiveAllExample.png) | +| :-----------------------------------------------------------: | +| All recently unarchived entries visible in the companies list | + +### 6.8. Removing entries + +#### 6.8.1. Deleting an entry : `delete` + +Deletes the specified entry from the currently displayed list. + +Format: + +``` +delete INDEX +``` + +- Deletes the entry at the specified `INDEX` of the currently displayed list. +- The index refers to the index number shown in the currently displayed list. +- The index **must be a positive integer** 1, 2, 3, …​ + +
:exclamation: **Caution:** +When a Company is deleted, all Persons and Events which store the company name of that Company will also be deleted. +
+ +Examples: + +- `listc` followed by `delete 2` deletes the 2nd company in the list of comapnies. +- `findp Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. + +| ![Deleting a company](images/DeleteEntryExample.png) | +| :-------------------------------------------------------: | +| DBS not showing in the companies list after being deleted | + +#### 6.8.2. Deleting all entries in display : `delete_all` + +Deletes all the entries displayed in the currently displayed list. + +Format: + +``` +delete_all +``` + +| ![Deleting all entries](images/DeleteAllExample.png) | +| :------------------------------------------------------------------------: | +| Empty list of events after using `delete_all` on the displayed events list | + +#### 6.8.3. Clearing all entries : `clear` + +Deletes all entries from all lists. + +Format: + +``` +clear +``` + +| ![Clear](images/ClearExample.png) | +| :------------------------------------------------: | +| Empty list of companies after clearing all entries | + +### 6.9. Exiting the program : `exit` Exits the program. -Format: `exit` +Format: + +``` +exit +``` + +### 6.10. Saving the data -### Saving the data +InternBuddy data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +### 6.11. Editing the data file -### Editing the data file +
:information_source: **Note:** This section is for advanced users only. +
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file. +InternBuddy data are saved as a JSON file `[JAR file location]/data/internbuddy.json`. Advanced users are welcome to update data directly by editing that data file.
:exclamation: **Caution:** -If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. +If your changes to the data file makes its format invalid, InternBuddy will discard all data and start with an empty data file at the next run.
-### Archiving data files `[coming in v2.0]` +--- + +## 7. That is All! -_Details coming soon ..._ +Congratulations! You have finished reading all InternBuddy has to offer. We the developers surely hope that +you find this User Guide to be useful as your personal Guide to become **InternBuddy Guru**. --------------------------------------------------------------------------------------------------------------------- +With that, Good Luck with your Internship! + +--- -## FAQ +## 8. FAQ **Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder. +**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous InternBuddy home folder. --------------------------------------------------------------------------------------------------------------------- +**Q**: Is InternBuddy development still in progress?
+**A**: Yes! InternBuddy is an active ongoing project. We hope to optimise the application to better suit our user! -## Command summary +--- + +## 9. Glossary + +- ### 9.1. CLI + CLI stands for Command Line Interface. It is a special type of terminal interface where you can type commands into it and the command will be executed. +- ### 9.2. Entry + An entry is a single entry in a list. In InternBuddy, an entry can be a company, a person, or an event. Entry is a generic term that can be used to refer to any of the three types of entries. +- ### 9.3. GUI + GUI stands for Graphical User Interface. Contrary to CLI, GUI is an interface that you can interact with, mainly through clicking interface (i.e. clicking buttons and menu). +- ### 9.4. JAR + JAR stands for Java Archive. It is a file format that is used to store data in a compressed format. The InternBuddy app is run in form of JAR. +- ### 9.5. JSON + JSON stands for JavaScript Object Notation. InternBuddy uses JSON files to store data. +- ### 9.6. Parameter + A parameter is a keyword that is used to specify a specific action. For example, `listp` is a command that lists all companies. `listp` has a parameter `s/` that specifies the type of entries to be listed. + +--- -Action | Format, Examples ---------|------------------ -**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​`
e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -**Clear** | `clear` -**Delete** | `delete INDEX`
e.g., `delete 3` -**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`
e.g.,`edit 2 n/James Lee e/jameslee@example.com` -**Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` -**List** | `list` -**Help** | `help` +## 10. Command summary + +| Action | Format | Examples | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| **Add Company** | `addc n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]… ` | `addc n/DBS t/bank e/dbs@example.com p/1234567 a/31 Race Road #02-03 t/finance` | +| **Add Person** | `addp n/NAME c/COMPANY_NAME p/PHONE_NUMBER e/EMAIL [t/TAG]… ` | `addp n/John Doe c/Shopee p/98765432 e/johnd@example.com t/friend t/colleague` | +| **Add Event** | `adde n/NAME c/COMPANY_NAME d/DATE ti/TIME l/LOCATION [t/TAG]… ` | `adde n/Career Talk c/Sony d/2022-03-19 ti/10:00 l/22 Clementi Rd t/important` | +| **Archive** | `archive INDEX` | `archive 2` | +| **Archive all in display** | `archive_all` | | +| **Clear** | `clear` | | +| **Delete** | `delete INDEX` | `delete 3` | +| **Delete all in display** | `delete_all` | | +| **Edit Company** | `editc INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…` | `editc 2 n/Shoppee t/` | +| **Edit Person** | `editp INDEX [n/NAME] [c/COMPANY_NAME] [p/PHONE] [e/EMAIL] [t/TAG]…` | `editp 1 p/91234567 e/johndoe@example.com` | +| **Edit Event** | `edite INDEX [n/NAME] [c/COMPANY_NAME] [d/DATE] [ti/TIME] [l/LOCATION] [t/TAG]…` | `edite 2 n/Resume Screening d/2022-12-11` | +| **Exit** | `exit` | | +| **Find Company** | `findc [n/NAME] [s/SEARCH_TYPE] [t/TAG]…` | `findc s/unarchived n/Shopee` | +| **Find Person** | `findp [n/NAME] [c/COMPANY_NAME] [s/SEARCH_TYPE] [t/TAG]…` | `findp n/James Jake` | +| **Find Event** | `finde [n/NAME] [c/COMPANY_NAME] [sd/START_DATE] [ed/END_DATE] [ti/TIME] [l/LOCATION] [s/SEARCH_TYPE] [t/TAG]…` | `finde s/all n/Career Talk sd/2022-01-01 ed/2022-03-14` | +| **Help** | `help` | | +| **List Companies** | `listc [s/SEARCH_TYPE]` | `listc` | +| **List Persons** | `listp [s/SEARCH_TYPE]` | `listp s/all` | +| **List Events** | `liste [s/SEARCH_TYPE]` | `liste s/archived` | +| **Sort Companies** | `sortc [s/SEARCH_TYPE] [o/ORDERING]` | `sortc` | +| **Sort Persons** | `sortp [s/SEARCH_TYPE] [o/ORDERING]` | `sortp s/unarchived o/ascending` | +| **Sort Events** | `sorte [s/SEARCH_TYPE] [o/ORDERING]` | `sortc o/descending s/archived` | +| **Unarchive** | `unarchive INDEX` | `unarchive 4` | +| **Unarchive all in display** | `unarchive_all` | | diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..341ade8b33a 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,4 +1,4 @@ -title: "AB-3" +title: "InternBuddy" theme: minima header_pages: @@ -8,7 +8,7 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +repository: "CS2103T-W14-3/tp/" github_icon: "images/github-icon.png" plugins: diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss index 0d3f6e80ced..f5be31f58ae 100644 --- a/docs/_sass/minima/_base.scss +++ b/docs/_sass/minima/_base.scss @@ -288,7 +288,7 @@ table { text-align: center; } .site-header:before { - content: "AB-3"; + content: "InternBuddy"; font-size: 32px; } } diff --git a/docs/diagrams/AddCompanySequenceDiagram1.puml b/docs/diagrams/AddCompanySequenceDiagram1.puml new file mode 100644 index 00000000000..c70aa796f6e --- /dev/null +++ b/docs/diagrams/AddCompanySequenceDiagram1.puml @@ -0,0 +1,19 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant "a:AddCompanyCommand" as AddXYZCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + + +AddXYZCommand -> Model : hasCompany() +activate AddXYZCommand +activate Model +Model --> AddXYZCommand : boolean +deactivate AddXYZCommand +deactivate Model +@enduml diff --git a/docs/diagrams/AddEventSequenceDiagram1.puml b/docs/diagrams/AddEventSequenceDiagram1.puml new file mode 100644 index 00000000000..4a2cfc46f53 --- /dev/null +++ b/docs/diagrams/AddEventSequenceDiagram1.puml @@ -0,0 +1,24 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant "a:AddEventCommand" as AddXYZCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +AddXYZCommand -> Model : hasEvent() +activate AddXYZCommand +activate Model +Model --> AddXYZCommand : boolean +deactivate Model +deactivate AddXYZCommand +AddXYZCommand -> Model : hasCompany() +activate AddXYZCommand +activate Model +Model --> AddXYZCommand : boolean +deactivate AddXYZCommand +deactivate Model +@enduml diff --git a/docs/diagrams/AddPersonSequenceDiagram1.puml b/docs/diagrams/AddPersonSequenceDiagram1.puml new file mode 100644 index 00000000000..96aee09c2dd --- /dev/null +++ b/docs/diagrams/AddPersonSequenceDiagram1.puml @@ -0,0 +1,24 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant "a:AddPersonCommand" as AddXYZCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +AddXYZCommand -> Model : hasPerson() +activate AddXYZCommand +activate Model +Model --> AddXYZCommand : boolean +deactivate Model +deactivate AddXYZCommand +AddXYZCommand -> Model : hasCompany() +activate AddXYZCommand +activate Model +Model --> AddXYZCommand : boolean +deactivate AddXYZCommand +deactivate Model +@enduml diff --git a/docs/diagrams/AddXYZActivityDiagram.puml b/docs/diagrams/AddXYZActivityDiagram.puml new file mode 100644 index 00000000000..fdc5851b48a --- /dev/null +++ b/docs/diagrams/AddXYZActivityDiagram.puml @@ -0,0 +1,27 @@ +@startuml +start +: User enter addXYZ command; +: AddXYZCommandParser parses command; + +if () then ([valid user input provided]) + :Create XYZ object; + :Create addXYZ command; + :Execute addXYZ Command; + if () then ([all valid parameter provided]) + if () then ([XYZ object exists in XYZ List]) + : Throw CommandException; + else ([XYZ object is new]) + : Calls Model to add the given XYZ object; + : Model interacts with AddressBook and add the XYZ object to XYZ list; + : Display success message; + endif + else ([invalid]) + : Throw CommandException; + : Display invalid parameter error message; + endif +else ([invalid]) + :Throw parse exception; + :Display invalid command error message; +endif +stop +@enduml diff --git a/docs/diagrams/AddXYZSequenceDiagram.puml b/docs/diagrams/AddXYZSequenceDiagram.puml new file mode 100644 index 00000000000..e3e4e407256 --- /dev/null +++ b/docs/diagrams/AddXYZSequenceDiagram.puml @@ -0,0 +1,87 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":AddXYZParser" as AddXYZParser LOGIC_COLOR +participant "a:AddXYZCommand" as AddXYZCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "xyz:XYZ" as XYZ MODEL_COLOR +end box + +[-> LogicManager : execute(addXYZexample) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(addXYZexample) +activate AddressBookParser + +create AddXYZParser +AddressBookParser -> AddXYZParser +activate AddXYZParser + +AddXYZParser --> AddressBookParser +deactivate AddXYZParser + +AddressBookParser -> AddXYZParser : parse(addXYZexample) +activate AddXYZParser + +create XYZ +AddXYZParser -> XYZ +activate XYZ + +XYZ --> AddXYZParser : xyz +deactivate XYZ +create AddXYZCommand +AddXYZParser -> AddXYZCommand : xyz +activate AddXYZCommand + +AddXYZCommand --> AddXYZParser : a +deactivate AddXYZCommand + +AddXYZParser --> AddressBookParser : a +deactivate AddXYZParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddXYZParser -[hidden]-> AddressBookParser +destroy AddXYZParser + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> AddXYZCommand : execute() +activate AddXYZCommand + +AddXYZCommand -> Model : hasXYZ(xyz) +activate Model +Model --> AddXYZCommand : boolean +deactivate Model + +AddXYZCommand -> Model : addXYZ(xyz) +activate Model + +Model -[hidden]-> AddXYZCommand +Model -[hidden]-> AddXYZCommand +Model --> AddXYZCommand +deactivate Model + +AddXYZCommand -[hidden]-> AddXYZCommand +create CommandResult +AddXYZCommand -> CommandResult +activate CommandResult + +CommandResult --> AddXYZCommand : result +deactivate CommandResult + +AddXYZCommand --> LogicManager : result +deactivate AddXYZCommand +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddXYZCommand -[hidden]-> AddressBookParser +destroy AddXYZCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index ef81d18c337..fe0f90a3168 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -13,7 +13,7 @@ activate ui UI_COLOR ui -[UI_COLOR]> logic : execute("delete 1") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteEntry(p) activate model MODEL_COLOR model -[MODEL_COLOR]-> logic diff --git a/docs/diagrams/ArchiveSequenceDiagram.puml b/docs/diagrams/ArchiveSequenceDiagram.puml new file mode 100644 index 00000000000..0e1847278dc --- /dev/null +++ b/docs/diagrams/ArchiveSequenceDiagram.puml @@ -0,0 +1,75 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":ArchiveCommandParser" as ArchiveCommandParser LOGIC_COLOR +participant "a:ArchiveCommand" as ArchiveCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("archive 1") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand("archive 1") +activate AddressBookParser + +create ArchiveCommandParser +AddressBookParser -> ArchiveCommandParser +activate ArchiveCommandParser + +ArchiveCommandParser --> AddressBookParser +deactivate ArchiveCommandParser + +AddressBookParser -> ArchiveCommandParser : parse("1") +activate ArchiveCommandParser + +create ArchiveCommand +ArchiveCommandParser -> ArchiveCommand +activate ArchiveCommand + +ArchiveCommand --> ArchiveCommandParser : a +deactivate ArchiveCommand + +ArchiveCommandParser --> AddressBookParser : a +deactivate ArchiveCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +ArchiveCommandParser -[hidden]-> AddressBookParser +destroy ArchiveCommandParser + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> ArchiveCommand : execute() +activate ArchiveCommand + +ArchiveCommand -> Model : archiveEntry(1) +activate Model + +Model --> ArchiveCommand +deactivate Model + +ArchiveCommand -> Model : updateCurrentlyDisplayedList() +activate Model + +Model --> ArchiveCommand +deactivate Model + +create CommandResult +ArchiveCommand -> CommandResult +activate CommandResult + +CommandResult --> ArchiveCommand +deactivate CommandResult + +ArchiveCommand --> LogicManager : result +deactivate ArchiveCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 5731f9cbaa1..23f20646e3a 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,18 +4,15 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -AddressBook *-right-> "1" UniquePersonList +Class "{abstract}\nEntry" as Entry + +AddressBook *-right-> "1" UniqueEntryList AddressBook *-right-> "1" UniqueTagList -UniqueTagList -[hidden]down- UniquePersonList -UniqueTagList -[hidden]down- UniquePersonList +UniqueTagList -[hidden]down- UniqueEntryList +UniqueTagList -[hidden]down- UniqueEntryList UniqueTagList *-right-> "*" Tag -UniquePersonList -right-> Person - -Person -up-> "*" Tag +UniqueEntryList -right-> Entry -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address +Entry -up-> "*" Tag @enduml diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..9f9019727ae 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -48,7 +48,7 @@ deactivate AddressBookParser LogicManager -> DeleteCommand : execute() activate DeleteCommand -DeleteCommand -> Model : deletePerson(1) +DeleteCommand -> Model : deleteEntry(1) activate Model Model --> DeleteCommand diff --git a/docs/diagrams/EntryClasses.puml b/docs/diagrams/EntryClasses.puml new file mode 100644 index 00000000000..790bd7e81cb --- /dev/null +++ b/docs/diagrams/EntryClasses.puml @@ -0,0 +1,48 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +Package "Entry classes" <>{ +Class "{abstract}\nEntry" as Entry +Class Company +Class Person +Class Event + +Class Address +Class Phone +Class Email +Class Tag +Class Name +Class CompanyName +Class Date +Class Time +Class Location +} + +Class HiddenOutside #FFFFFF +HiddenOutside ..> Entry + +Company -up-|> Entry +Person -up-|> Entry +Event -up-|> Entry + +Company *-down-> Address +Company *-down-> Phone +Company *-down-> Email + +Person *-down-> Phone +Person *-down-> Email +Person *-down-> CompanyName + +Event *-down-> CompanyName +Event *-down-> Date +Event *-down-> Time +Event *-down-> Location + +CompanyName -up-|> Name +Entry *--> Name +Entry *--> "*" Tag + +@enduml diff --git a/docs/diagrams/FindXYZActivityDiagram.puml b/docs/diagrams/FindXYZActivityDiagram.puml new file mode 100644 index 00000000000..f2c8c6c2506 --- /dev/null +++ b/docs/diagrams/FindXYZActivityDiagram.puml @@ -0,0 +1,24 @@ +@startuml +start +: User enter findXYZ command; +: FindXYZCommandParser parses command; + +if () then ([valid user input provided]) + :Create XYZContainsKeywords predicate; + :Create findXYZ command; + :Execute findXYZ Command; + if () then ([all valid parameter provided]) + : Calls Model to show the queried XYZ entry; + : Model interacts with AddressBook and filter the XYZ list; + : Model display only the XYZ list; + : Display success message; + else ([invalid]) + : Throw CommandException; + : Display invalid parameter error message; + endif +else ([invalid]) + :Throw parse exception; + :Display invalid command error message; +endif +stop +@enduml diff --git a/docs/diagrams/FindXYZSequenceDiagram.puml b/docs/diagrams/FindXYZSequenceDiagram.puml new file mode 100644 index 00000000000..0a676b132d2 --- /dev/null +++ b/docs/diagrams/FindXYZSequenceDiagram.puml @@ -0,0 +1,79 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":FindXYZParser" as FindXYZParser LOGIC_COLOR +participant "a:FindXYZCommand" as FindXYZCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "p:XYZContainsKeywordsPredicate" as PREDICATE MODEL_COLOR +end box + +[-> LogicManager : execute(findXYZexample) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(findXYZexample) +activate AddressBookParser + +create FindXYZParser +AddressBookParser -> FindXYZParser +activate FindXYZParser + +FindXYZParser --> AddressBookParser +deactivate FindXYZParser + +AddressBookParser -> FindXYZParser : parse(findXYZexample) +activate FindXYZParser + +create PREDICATE +FindXYZParser -> PREDICATE +activate PREDICATE + +PREDICATE --> FindXYZParser : p +deactivate PREDICATE +create FindXYZCommand +FindXYZParser -> FindXYZCommand : p +activate FindXYZCommand + +FindXYZCommand --> FindXYZParser : a +deactivate FindXYZCommand + +FindXYZParser --> AddressBookParser : a +deactivate FindXYZParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +FindXYZParser -[hidden]-> AddressBookParser +destroy FindXYZParser + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> FindXYZCommand : execute() +activate FindXYZCommand + +FindXYZCommand -> Model : showXYZList(p) +activate Model +Model --> FindXYZCommand +deactivate Model + +FindXYZCommand -[hidden]-> FindXYZCommand +create CommandResult +FindXYZCommand -> CommandResult +activate CommandResult + +CommandResult --> FindXYZCommand : result +deactivate CommandResult + +FindXYZCommand --> LogicManager : result +deactivate FindXYZCommand +'Hidden arrow to position the destroy marker below the end of the activation bar. +FindXYZCommand -[hidden]-> AddressBookParser +destroy FindXYZCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index d4193173e18..dd804ffcf91 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -38,7 +38,7 @@ LogicManager --> Storage Storage --[hidden] Model Command .[hidden]up.> Storage Command .right.> Model -note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc +note right of XYZCommand: XYZCommand = DeleteCommand, \nAddPersonCommand, etc Logic ..> CommandResult LogicManager .down.> CommandResult diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 4439108973a..fe8e6287757 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -12,13 +12,8 @@ Class AddressBook Class ModelManager Class UserPrefs -Class UniquePersonList -Class Person -Class Address -Class Email -Class Name -Class Phone -Class Tag +Class UniqueEntryList +Class "{abstract}\nEntry" as Entry } @@ -34,17 +29,8 @@ ModelManager -left-> "1" AddressBook ModelManager -right-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList -UniquePersonList --> "~* all" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag +AddressBook *--> "3" UniqueEntryList +UniqueEntryList --> "~* all" Entry -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email - -ModelManager -->"~* filtered" Person +ModelManager -->"~* filtered" Entry @enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 760305e0e58..2a7ed7140fb 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -19,6 +19,8 @@ Class "<>\nAddressBookStorage" as AddressBookStorage Class JsonAddressBookStorage Class JsonSerializableAddressBook Class JsonAdaptedPerson +Class JsonAdaptedCompany +Class JsonAdaptedEvent Class JsonAdaptedTag } @@ -38,6 +40,10 @@ JsonUserPrefsStorage .up.|> UserPrefsStorage JsonAddressBookStorage .up.|> AddressBookStorage JsonAddressBookStorage ..> JsonSerializableAddressBook JsonSerializableAddressBook --> "*" JsonAdaptedPerson +JsonSerializableAddressBook --> "*" JsonAdaptedEvent +JsonSerializableAddressBook --> "*" JsonAdaptedCompany JsonAdaptedPerson --> "*" JsonAdaptedTag +JsonAdaptedCompany --> "*" JsonAdaptedTag +JsonAdaptedEvent --> "*" JsonAdaptedTag @enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 95473d5aa19..386d28fb8dc 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -11,8 +11,13 @@ Class UiManager Class MainWindow Class HelpWindow Class ResultDisplay +Class EntryListPanel Class PersonListPanel +Class CompanyListPanel +Class EventListPanel Class PersonCard +Class CompanyCard +Class EventCard Class StatusBarFooter Class CommandBox } @@ -32,10 +37,15 @@ UiManager .left.|> Ui UiManager -down-> "1" MainWindow MainWindow *-down-> "1" CommandBox MainWindow *-down-> "1" ResultDisplay -MainWindow *-down-> "1" PersonListPanel +MainWindow *-down-> "1" EntryListPanel +EntryListPanel *-down-> "0..1" PersonListPanel +EntryListPanel *-down-> "0..1" CompanyListPanel +EntryListPanel *-down-> "0..1" EventListPanel MainWindow *-down-> "1" StatusBarFooter MainWindow --> "0..1" HelpWindow +CompanyListPanel -down-> "*" CompanyCard +EventListPanel -down-> "*" EventCard PersonListPanel -down-> "*" PersonCard MainWindow -left-|> UiPart @@ -43,11 +53,17 @@ MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart PersonListPanel --|> UiPart +CompanyListPanel --|> UiPart +EventListPanel --|> UiPart PersonCard --|> UiPart +EventCard --|> UiPart +CompanyCard --|> UiPart StatusBarFooter --|> UiPart HelpWindow --|> UiPart PersonCard ..> Model +CompanyCard ..> Model +EventCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml index 01fcb9b2b96..ae7191119ae 100644 --- a/docs/diagrams/UndoRedoState1.puml +++ b/docs/diagrams/UndoRedoState1.puml @@ -16,7 +16,7 @@ State2 -[hidden]right-> State3 hide State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State2 @end diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml index bccc230a5d1..b6705014fff 100644 --- a/docs/diagrams/UndoRedoState2.puml +++ b/docs/diagrams/UndoRedoState2.puml @@ -3,7 +3,7 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "add n/David" +title After command "addp n/David ......" package States <> { class State1 as "__ab0:AddressBook__" @@ -14,7 +14,7 @@ package States <> { State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State3 @end diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml index ea29c9483e4..90b45904723 100644 --- a/docs/diagrams/UndoRedoState3.puml +++ b/docs/diagrams/UndoRedoState3.puml @@ -14,7 +14,7 @@ package States <> { State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 -class Pointer as "Current State" #FFFFF +class Pointer as "Current State" Pointer -up-> State2 @end diff --git a/docs/diagrams/test.puml b/docs/diagrams/test.puml new file mode 100644 index 00000000000..e3e4e407256 --- /dev/null +++ b/docs/diagrams/test.puml @@ -0,0 +1,87 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":AddXYZParser" as AddXYZParser LOGIC_COLOR +participant "a:AddXYZCommand" as AddXYZCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "xyz:XYZ" as XYZ MODEL_COLOR +end box + +[-> LogicManager : execute(addXYZexample) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(addXYZexample) +activate AddressBookParser + +create AddXYZParser +AddressBookParser -> AddXYZParser +activate AddXYZParser + +AddXYZParser --> AddressBookParser +deactivate AddXYZParser + +AddressBookParser -> AddXYZParser : parse(addXYZexample) +activate AddXYZParser + +create XYZ +AddXYZParser -> XYZ +activate XYZ + +XYZ --> AddXYZParser : xyz +deactivate XYZ +create AddXYZCommand +AddXYZParser -> AddXYZCommand : xyz +activate AddXYZCommand + +AddXYZCommand --> AddXYZParser : a +deactivate AddXYZCommand + +AddXYZParser --> AddressBookParser : a +deactivate AddXYZParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddXYZParser -[hidden]-> AddressBookParser +destroy AddXYZParser + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> AddXYZCommand : execute() +activate AddXYZCommand + +AddXYZCommand -> Model : hasXYZ(xyz) +activate Model +Model --> AddXYZCommand : boolean +deactivate Model + +AddXYZCommand -> Model : addXYZ(xyz) +activate Model + +Model -[hidden]-> AddXYZCommand +Model -[hidden]-> AddXYZCommand +Model --> AddXYZCommand +deactivate Model + +AddXYZCommand -[hidden]-> AddXYZCommand +create CommandResult +AddXYZCommand -> CommandResult +activate CommandResult + +CommandResult --> AddXYZCommand : result +deactivate CommandResult + +AddXYZCommand --> LogicManager : result +deactivate AddXYZCommand +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddXYZCommand -[hidden]-> AddressBookParser +destroy AddXYZCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/images/AddCompanyExample.png b/docs/images/AddCompanyExample.png new file mode 100644 index 00000000000..38e3d5b2dc3 Binary files /dev/null and b/docs/images/AddCompanyExample.png differ diff --git a/docs/images/AddCompanySequenceDiagram1.png b/docs/images/AddCompanySequenceDiagram1.png new file mode 100644 index 00000000000..8949f9be629 Binary files /dev/null and b/docs/images/AddCompanySequenceDiagram1.png differ diff --git a/docs/images/AddEventExample.png b/docs/images/AddEventExample.png new file mode 100644 index 00000000000..00b19120813 Binary files /dev/null and b/docs/images/AddEventExample.png differ diff --git a/docs/images/AddEventSequenceDiagram1.png b/docs/images/AddEventSequenceDiagram1.png new file mode 100644 index 00000000000..e0a5dc64b85 Binary files /dev/null and b/docs/images/AddEventSequenceDiagram1.png differ diff --git a/docs/images/AddPersonExample.png b/docs/images/AddPersonExample.png new file mode 100644 index 00000000000..75990efb3a2 Binary files /dev/null and b/docs/images/AddPersonExample.png differ diff --git a/docs/images/AddPersonSequenceDiagram1.png b/docs/images/AddPersonSequenceDiagram1.png new file mode 100644 index 00000000000..df41e15fcf2 Binary files /dev/null and b/docs/images/AddPersonSequenceDiagram1.png differ diff --git a/docs/images/AddXYZActivityDiagram.png b/docs/images/AddXYZActivityDiagram.png new file mode 100644 index 00000000000..7e65cae4c76 Binary files /dev/null and b/docs/images/AddXYZActivityDiagram.png differ diff --git a/docs/images/AddXYZSequenceDiagram.png b/docs/images/AddXYZSequenceDiagram.png new file mode 100644 index 00000000000..857125d189e Binary files /dev/null and b/docs/images/AddXYZSequenceDiagram.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 2f1346869d0..b4ab7937c55 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/ArchiveAllExample.png b/docs/images/ArchiveAllExample.png new file mode 100644 index 00000000000..e3dcd5387ae Binary files /dev/null and b/docs/images/ArchiveAllExample.png differ diff --git a/docs/images/ArchiveEntryExample.png b/docs/images/ArchiveEntryExample.png new file mode 100644 index 00000000000..08f783fe595 Binary files /dev/null and b/docs/images/ArchiveEntryExample.png differ diff --git a/docs/images/ArchiveSequenceDiagram.png b/docs/images/ArchiveSequenceDiagram.png new file mode 100644 index 00000000000..26b2eb98cac Binary files /dev/null and b/docs/images/ArchiveSequenceDiagram.png differ diff --git a/docs/images/ArchivedEntryExample.png b/docs/images/ArchivedEntryExample.png new file mode 100644 index 00000000000..4810b130d6d Binary files /dev/null and b/docs/images/ArchivedEntryExample.png differ diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png index 1ec62caa2a5..57cc8988e8f 100644 Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ diff --git a/docs/images/ClearExample.png b/docs/images/ClearExample.png new file mode 100644 index 00000000000..0d7cafa3a66 Binary files /dev/null and b/docs/images/ClearExample.png differ diff --git a/docs/images/DeleteAllExample.png b/docs/images/DeleteAllExample.png new file mode 100644 index 00000000000..b00d20bf725 Binary files /dev/null and b/docs/images/DeleteAllExample.png differ diff --git a/docs/images/DeleteEntryExample.png b/docs/images/DeleteEntryExample.png new file mode 100644 index 00000000000..e04e145ef26 Binary files /dev/null and b/docs/images/DeleteEntryExample.png differ diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png index fa327b39618..6fe7c410f19 100644 Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ diff --git a/docs/images/EditCompanyExample.png b/docs/images/EditCompanyExample.png new file mode 100644 index 00000000000..d8dbfdb3d43 Binary files /dev/null and b/docs/images/EditCompanyExample.png differ diff --git a/docs/images/EditEventExample.png b/docs/images/EditEventExample.png new file mode 100644 index 00000000000..bafd4b38088 Binary files /dev/null and b/docs/images/EditEventExample.png differ diff --git a/docs/images/EditPersonExample.png b/docs/images/EditPersonExample.png new file mode 100644 index 00000000000..c1270928e25 Binary files /dev/null and b/docs/images/EditPersonExample.png differ diff --git a/docs/images/EntryClasses.png b/docs/images/EntryClasses.png new file mode 100644 index 00000000000..db41185f2fc Binary files /dev/null and b/docs/images/EntryClasses.png differ diff --git a/docs/images/FindCompanyExample.png b/docs/images/FindCompanyExample.png new file mode 100644 index 00000000000..98a8e106f38 Binary files /dev/null and b/docs/images/FindCompanyExample.png differ diff --git a/docs/images/FindEventExample.png b/docs/images/FindEventExample.png new file mode 100644 index 00000000000..acdab4e839c Binary files /dev/null and b/docs/images/FindEventExample.png differ diff --git a/docs/images/FindXYZActivityDiagram.png b/docs/images/FindXYZActivityDiagram.png new file mode 100644 index 00000000000..dc231036785 Binary files /dev/null and b/docs/images/FindXYZActivityDiagram.png differ diff --git a/docs/images/FindXYZSequenceDiagram.png b/docs/images/FindXYZSequenceDiagram.png new file mode 100644 index 00000000000..81a1c8179cb Binary files /dev/null and b/docs/images/FindXYZSequenceDiagram.png differ diff --git a/docs/images/InvalidCommandMessageExample.png b/docs/images/InvalidCommandMessageExample.png new file mode 100644 index 00000000000..3b02d8a605c Binary files /dev/null and b/docs/images/InvalidCommandMessageExample.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index 9e9ba9f79e5..f85b0484f68 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index 04070af60d8..fe8a1932024 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/ParameterErrorExample.png b/docs/images/ParameterErrorExample.png new file mode 100644 index 00000000000..5be78c0cf51 Binary files /dev/null and b/docs/images/ParameterErrorExample.png differ diff --git a/docs/images/SortAscendingExample.png b/docs/images/SortAscendingExample.png new file mode 100644 index 00000000000..55c2cb8391f Binary files /dev/null and b/docs/images/SortAscendingExample.png differ diff --git a/docs/images/SortDescendingExample.png b/docs/images/SortDescendingExample.png new file mode 100644 index 00000000000..86937aa14a1 Binary files /dev/null and b/docs/images/SortDescendingExample.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index 2533a5c1af0..7621b99670b 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/SuccessfulCommandExample.png b/docs/images/SuccessfulCommandExample.png new file mode 100644 index 00000000000..cc79df81d6d Binary files /dev/null and b/docs/images/SuccessfulCommandExample.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..78990e73a49 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 785e04dbab4..ed6b0901c5d 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/UnarchiveAllExample.png b/docs/images/UnarchiveAllExample.png new file mode 100644 index 00000000000..79b55c5881a Binary files /dev/null and b/docs/images/UnarchiveAllExample.png differ diff --git a/docs/images/UnarchiveEntryExample.png b/docs/images/UnarchiveEntryExample.png new file mode 100644 index 00000000000..4508173e30b Binary files /dev/null and b/docs/images/UnarchiveEntryExample.png differ diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png index df9908d0948..202d0cf22e6 100644 Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png index 36519c1015b..0ffc26a5a4d 100644 Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png index 19959d01712..b46a223d145 100644 Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ diff --git a/docs/images/UserGuide/Command-Box.png b/docs/images/UserGuide/Command-Box.png new file mode 100644 index 00000000000..540c8f439f9 Binary files /dev/null and b/docs/images/UserGuide/Command-Box.png differ diff --git a/docs/images/UserGuide/Ui-1.png b/docs/images/UserGuide/Ui-1.png new file mode 100644 index 00000000000..10caac0f9db Binary files /dev/null and b/docs/images/UserGuide/Ui-1.png differ diff --git a/docs/images/UserGuide/Ui-2.png b/docs/images/UserGuide/Ui-2.png new file mode 100644 index 00000000000..f8c5f532208 Binary files /dev/null and b/docs/images/UserGuide/Ui-2.png differ diff --git a/docs/images/UserGuide/Ui-3.png b/docs/images/UserGuide/Ui-3.png new file mode 100644 index 00000000000..7b01b8ed9ef Binary files /dev/null and b/docs/images/UserGuide/Ui-3.png differ diff --git a/docs/images/UserGuide/Ui-4.png b/docs/images/UserGuide/Ui-4.png new file mode 100644 index 00000000000..349b9dc933d Binary files /dev/null and b/docs/images/UserGuide/Ui-4.png differ diff --git a/docs/images/UserGuide/Ui-annotated.png b/docs/images/UserGuide/Ui-annotated.png new file mode 100644 index 00000000000..47f978d078b Binary files /dev/null and b/docs/images/UserGuide/Ui-annotated.png differ diff --git a/docs/images/albertsutz.png b/docs/images/albertsutz.png new file mode 100644 index 00000000000..e8354db15b4 Binary files /dev/null and b/docs/images/albertsutz.png differ diff --git a/docs/images/findAlexDavidResult.png b/docs/images/findAlexDavidResult.png index 235da1c273e..c1c24645a23 100644 Binary files a/docs/images/findAlexDavidResult.png and b/docs/images/findAlexDavidResult.png differ diff --git a/docs/images/graphcalibur.png b/docs/images/graphcalibur.png new file mode 100644 index 00000000000..1a421abb58a Binary files /dev/null and b/docs/images/graphcalibur.png differ diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png index b1f70470137..2135c1de23f 100644 Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ diff --git a/docs/images/johndoe.png b/docs/images/johndoe.png deleted file mode 100644 index 1ce7ce16dc8..00000000000 Binary files a/docs/images/johndoe.png and /dev/null differ diff --git a/docs/images/mradhyaf.png b/docs/images/mradhyaf.png new file mode 100755 index 00000000000..1db318ecd09 Binary files /dev/null and b/docs/images/mradhyaf.png differ diff --git a/docs/images/theprevailingone.png b/docs/images/theprevailingone.png new file mode 100644 index 00000000000..b3140356d5c Binary files /dev/null and b/docs/images/theprevailingone.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..c228cc021af 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,54 @@ --- layout: page -title: AddressBook Level-3 +title: InternBuddy --- -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) -[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3) +[![CI Status](https://github.com/AY2122S2-CS2103T-W14-3/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103T-W14-3/tp/actions) +[![codecov](https://codecov.io/gh/AY2122S2-CS2103T-W14-3/tp/branch/master/graph/badge.svg?token=IHVW9KCP82)](https://codecov.io/gh/AY2122S2-CS2103T-W14-3/tp) ![Ui](images/Ui.png) -**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +# InternBuddy -* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). -* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. +**InternBuddy** is a desktop app for managing companies for internships, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). +If you can type fast, InternBuddy can get your internship management deliverables done faster than traditional GUI apps. + +--- + +### What can InternBuddy do? + +InternBuddy provides you a way to plan and organize all your internship details on a single application, with intuitive +UI to make your Job Seeking journey a smooth road. + +InternBuddy allows you to: +* Store and manage Companies +* Manage Contacts + * For example: Hiring Manager Contact Details +* Manage Events + * For example: Interviews and Online Assessments + +--- + +### Why InternBuddy? + +We believe that your time is precious. Rather than spending your time to organise your +internship particulars, you should utilise your time to improve your skills towards success such as +preparing your interview skills. With that, let InternBuddy works its magic to organise and manage your internship applications. + +However, InternBuddy really shines for managing a huge number of applications. The ease of filtering through +all the details with just a few keyboard clicks is a lightning fast feature that you will not encounter +using common GUI applications. + +--- +* Interested in trying InternBuddy? Head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start) and + save your time now!. +* If you are a developer looking to learn the mechanism of InternBuddy, we suggest you to look at +the [**Developer Guide**](DeveloperGuide.html)! + +--- **Acknowledgements** +* This application was built from AddressBook-Level-3 project created by [SE-EDU initiative](https://se-education.org). * Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5) diff --git a/docs/team/albertsutz.md b/docs/team/albertsutz.md new file mode 100644 index 00000000000..84b615d4a3d --- /dev/null +++ b/docs/team/albertsutz.md @@ -0,0 +1,90 @@ +--- +layout: page +title: Albertsutz's Project Portfolio Page +--- +### Project: InternBuddy + +InternBuddy is a desktop app that helps undergraduate students keep track of the companies they've +applied to for internships as well as any events you've arranged with them. It is optimized for +CLI users who prefer to type commands for efficiency. + +Efficiency and ease of use are two of InternBuddy's principle when +designing the application. It provides a lot of functionalities catered specifically for those looking for internships +which come from a real conducted survey. + +Given below are my contributions to the project. + +* **Code contributed**: I personally coded around 5k LoC(lines of code) which can be found in [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=albertsutz). +This includes `Documentation`, `Feature Code` (around >= 1.9k LoC), and `Unit Tests` (around >= 2.8k LoC) + +With every feature that I have implemented, I made sure to include the proper test to improve future extendability. + +* **Enhancements to existing features**: + * Find Person Command and Find Person Command Parser + * A feature to find people in InternBuddy by the combination of its name, companyName, and tags. This is an enhanced version of the initial command from ab3 + as it provides more attributes to be searched. + * Created PersonContainsKeywordsPredicate - an all-in-one person predicate used in FindPersonCommand + * List Person Command + * A feature to list all people in InternBuddy. + * Add better colour coding to archived and tags to enhance InternBuddy UI + * Make sure that all `Label` text wraps around and is not truncated. +* **New Command Features Implemented**: + * Create Event Class + * Event class has multiple additional attributes, in particular Date, Time, and Location. Thus, I contributed to code these additional 3 attributes. + * Create `Date`, `Time`, and `Location` Class + * Find Event Command and Find Event Command Parser + * A feature to filter events in InternBuddy by the combination of its name, companyName, date, time, location, and tags. + * Created EventContainsKeywordsPredicate - an all-in-one event predicate used in FindEventCommand + * Find Company Command and Find Company Command Parser + * A feature to filter companies in InternBuddy by the combination of its name and tags. + * Created CompanyContainsKeywordsPredicate - an all-in-one company predicate used in FindCompanyCommand + * List Event Command + * List Company Command + * Add Event Command + * As I have created the Event Command, I also contributed to the AddEventCommand to let users add Events. + * Comprehensive Automated Tests: + * `Add`, `Find`, and `Edit` command for `Event` and `Company` along with their `CommandParser` +* **Team-based Tasks Contributions and Project Management**: + * Put forward the idea of creating an app that manage internship applications + * Update GitHub Repository `README.md` and `Index.md` contents + * Remove all occurrences of ab3 in User Guide to InternBuddy(in the initial contributions) + * Found and implemented major hotfixes right before v1.3.0 +* **Review/mentoring contributions and Project Management** + * Created 23 Pull Requests and Provided over 21 non trivial comments which can be seen in this [reposense](https://nus-cs2103-ay2122s2.github.io/dashboards/contents/tp-comments.html) + * Contributed by reviewing most team members' pull request (with 5+ non trivial reviews) + * Managed Releases v1.2.0 and v1.3.0 +* **Community** + * Contributed to submitting issues to other team which can be found [here](https://github.com/albertsutz/ped) + Notice that the issues submitted often contains multiple bugs in 1 issue. +* **Effort** + * The new features that I have implemented took a lot of effort and are essential to the application. This is because my implementation deals with + basic commands that can make or break the application. With each command come careful planning and comprehensive manual testing to make sure that + the code does not break. Furthermore, as most of my implementation deals with new `Entry` type (`Event` and `Company`), they are not easily copy-pasted + from any sources. + * These testing are made exactly to make sure that the tests were accurate and covered a lot of the functions. In particular, + from this testing, there were some medium level bugs found which would be detrimental to the application. +* **User Guide Contribution** + * Initial contributions to User Guide + * Update `Quick Start` + * Created `Overview of InternBuddy` + * Contributes in `Introduction` + * Contributes in `Structure of InternBuddy` + * Contributes in `liste`, `editc` commands +* **Developer Guide Contribution** + * Added Implementation for `add` feature + * This includes all three implementation of `add event`, `add company`, and `add person`. + * Added Implementation for `find` feature + * This includes all three implementation of `find event`, `find company`, and `find person`. + * Added Manual testing for multiple features: + * `add company`, `add person`, and `add event` manual tests + * `find company`, `find person`, and `find event` manual tests + * `edit company`, `edit person` and `edit event` manual tests + * UML contributed: + * Updated [StorageClassDiagram](../images/StorageClassDiagram.png) + * Create [AddXYZSequenceDiagram](../images/AddXYZSequenceDiagram.png) + * Create [AddXYZActivityDiagram](../images/AddXYZActivityDiagram.png) + * Create [AddCompanySequenceDiagram1](../images/AddCompanySequenceDiagram1.png) + * Create [AddEventSequenceDiagram1](../images/AddEventSequenceDiagram1.png) + * Create [AddPersonSequenceDiagram1](../images/AddPersonSequenceDiagram1.png) + * Create [FindXYZSequenceDiagram](../images/FindXYZSequenceDiagram.png) + * Create [FindXYZActivityDiagram](../images/FindXYZActivityDiagram.png) diff --git a/docs/team/graphcalibur.md b/docs/team/graphcalibur.md new file mode 100644 index 00000000000..882ceaccc0e --- /dev/null +++ b/docs/team/graphcalibur.md @@ -0,0 +1,117 @@ +--- +layout: page +title: Graphcalibur's Project Portfolio Page +--- + +### Project: InternBuddy + +InternBuddy is a desktop app that helps undergraduate students keep track of the companies they've +applied to for internships as well as any events you've arranged with them. It is optimized for +CLI users who prefer to type commands for efficiency. + +Given below are my contributions to the project. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=graphcalibur&breakdown=true) + +* **New Feature**: Added support for multiple kinds of Entries + * What it does: AddressBook can now hold multiple types of entry lists, where each type of entry stores different attributes compared + to the others + * Justification: InternBuddy needed to support Person, Company, and Event lists. To do this without overly duplicating + code, the program needed to be retooled to be easily extended to support multiple types of entries. + * Highlights: This required creating a generic Entry class that all entry types would inherit from, as well as overhauling + the UniquePersonList into a UniqueEntryList so that it can hold and perform operations on any type of Entry. It also + involved refactoring much of the existing test code. + +* **New Feature**: Added support for Companies + * What it does: AddressBook now has a list of Companies and can perform Add and Edit commands on it. + * Justification: InternBuddy needed to support a list of Companies as that was one of its key features. + * Highlights: The existing commands and classes had to be extended to work on the list of Companies as well, which meant + creating an AddCompany and EditCompany commands. Furthermore, it also needed to be enforced that all Persons/Events must + refer to an existing Company with their companyName attribute. This involved a lot of overhead to update the Person and Event + lists whenever a Company gets edited/deleted. + +* **New Feature**: Added ability to archive entries + * What it does: Entries can be archived, which "hides" them from being displayed in the entry lists without deleting + them entirely. Archived entries can still be searched for but by default they are not shown unless specified. + * Justification: This feature allows users to hide entries which, while no longer relevant, they may still want to keep + either for posterity or just in case they need the information again. + * Highlights: This feature required overhauling the List and Find commands as both commands needed to take in an additional + parameter so that the user can choose whether to list/find all entries, only unarchived entries, or only archived entries. + It also required adding an extra attribute to Entries and creating new predicates to apply to the EntryLists. + +* **New Feature**: Added Date and Time validation for Date and Time attributes + * What it does: Date and Time parameters for Adding/Editing entries must now be in the correct format + * Justification: The program needs to ensure a consistent formatting standard for its Date and Time so that they can + be displayed in a nicer format and compared with each other. + * Highlights: This feature required using the LocalDate and LocalTime libraries. There was also a lot of string checking + involved in order to support the `today` and `today X` format for Dates. + +* **New Feature**: Added commands to apply to all displayed entries (for Archive, Delete, and Unarchive) + * What it does: All displayed entries can be archived/deleted/unarchived with a single command + * Justification: Deleting/archiving/unarchiving one by one can get very tedious + * Highlights: This feature mainly involved applying the operation to each element in the list one-by-one until it was done. + +* **New Feature**: Added Start Date and End Date parameters for FindEventCommand + * What it does: FindEventCommand can now take in Start Date and End Date parameters and return events between the two + dates + * Justification: It makes it a lot easier to find events within a certain date + * Highlights: This feature involved refactoring the FindEventCommand to take in these new parameters as well as + editing the predicates to compare the Dates. + +* **Team-Based Tasks**: + * Posted demo screenshots in the documents + * Organized Zoom meetings + * Set up project repository and settings + * Set up Codecov for the repository + * Managed release v1.3.1 on GitHub + * Set up and managed milestones v1.2, v1.3, and v1.4 + * Added many issues to the issue tracker and assigned them labels + +* **Reviewing/Mentoring Contributions** + * PRs reviewed: #17, #19, #20, #28, #32, #33, #34, #37, #41, #43, #44, #45, #47, #48, #74,#75, #81, #86, #89, #143, #148, #152, #155, #159 + * Helped teammates out in understanding the codebase + +* **Enhancements to existing features**: + * Generalized DeleteCommand to apply to any type of list + * Extended AddressBook, ModelManager, and ParserUtil to support new features + * Fixed bugs during v1.4 + +* **Documentation**: + * User Guide: + * Updated user guide to include v1.2 and some v1.3 features + * Add section explaining the restrictions on each parameter type + * Add section explaining Archive feature of InternBuddy + * Streamlined wording and fixed errors throughout the guide to make it smoother to read + * Developer Guide: + * Added user stories + * Added NFRs + * Updated value proposition and target profile + * Added section on design and implementation of Archive command + * Updated Design section to match InternBuddy v1.4, including UML diagrams + +* **Tests**: + * Wrote tests for the following files: + * `ListCompanyCommand` + * `ListPersonCommand` + * `ListEventCommand` + * `ListCommandParser` + * `Company` + * `Date` + * `Location` + * `Time` + * `ArchiveCommand` + * `ArchiveAllCommand` + * `UnarchiveCommand` + * `UnarchiveAllCommand` + * `ArchiveCommandParser` + * `UnarchiveCommandParser` + * `DeleteAllCommand` + * Also contributed to tests for the following files: + * `FindPersonCommandParser` + * `FindEventCommandParser` + * `FindCompanyCommandParser` + * `AddressBookParser` + * `EditPersonCommand` + * `EditEventCommand` + * `AddPersonCommand` + * `AddEventCommand` diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index 773a07794e2..00000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: page -title: John Doe's Project Portfolio Page ---- - -### Project: AddressBook Level 3 - -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. - -Given below are my contributions to the project. - -* **New Feature**: Added the ability to undo/redo previous commands. - * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. - * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. - * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. - * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}* - -* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys. - -* **Code contributed**: [RepoSense link]() - -* **Project management**: - * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub - -* **Enhancements to existing features**: - * Updated the GUI color scheme (Pull requests [\#33](), [\#34]()) - * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]()) - -* **Documentation**: - * User Guide: - * Added documentation for the features `delete` and `find` [\#72]() - * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]() - * Developer Guide: - * Added implementation details of the `delete` feature. - -* **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) - * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]()) - -* **Tools**: - * Integrated a third party library (Natty) to the project ([\#42]()) - * Integrated a new Github plugin (CircleCI) to the team repo - -* _{you can add/remove categories in the list above}_ diff --git a/docs/team/mradhyaf.md b/docs/team/mradhyaf.md new file mode 100644 index 00000000000..65be0c642e8 --- /dev/null +++ b/docs/team/mradhyaf.md @@ -0,0 +1,44 @@ +--- +layout: page +title: Mradhyaf's Project Portfolio Page +--- + +### Project: InternBuddy + +InternBuddy is a desktop app that helps undergraduate students keep track of the companies they've +applied to for internships as well as any events you've arranged with them. It is optimized for +CLI users who prefer to type commands for efficiency. + +InternBuddy is specialised for fast-typing users which is the main feature of the application. Efficiency and ease of use are two of InternBuddy's principle when +designing the application. It provides a lot of functionalities catered specifically for those looking for internships +which come from a real conducted survey. + +Given below are my contributions to the project. + +* **Code contributed**: [RepoSense link]() + +* **Enhancements implemented**: + * Add Delete Company Command + * Command to delete a company entry + * Improve Graphical User Interface + * Change color theme + * Add list title to describe the current viewed list + * Rearrange components for a more intuitive experience + * Add an InternBuddy app header + +* **Contributions to the UG**: + * Contribute idea to add `Guide Walkthrough` section, now called `Features Guide` + +* **Contributions to the DG**: + * Write use cases for editing, deleting, and locating features + +* **Contributions to team-based tasks**: + * Suggested InternBuddy name with the help of online tools + * Create InternBuddy icon + * Create InternBuddy mock UI + +* **Review/mentoring contributions**: + * Reviewed 3 Pull Requests + +* **Community**: + * Reported 2 non-trivial bugs to HireLah! ([1](https://github.com/AY2122S2-CS2103-W17-4/tp/issues/250), [2](https://github.com/AY2122S2-CS2103-W17-4/tp/issues/242)) diff --git a/docs/team/theprevailingone.md b/docs/team/theprevailingone.md new file mode 100644 index 00000000000..8be1927cb5f --- /dev/null +++ b/docs/team/theprevailingone.md @@ -0,0 +1,53 @@ +--- +layout: page +title: Edward Alvin's Project Portfolio Page +--- + +### Project: InternBuddy + +InternBuddy is a desktop app that helps undergraduate students keep track of the companies they’ve applied to for internships as well as any events you’ve arranged with them. It is optimized for CLI users who prefer to type commands for efficiency. + +InternBuddy is specialised for fast-typing users which is the main feature of the application. Efficiency and ease of use are two of InternBuddy’s principle when designing the application. It provides a lot of functionalities catered specifically for those looking for internships which come from a real conducted survey. + +Given below are my contributions to the project. + +* **New Feature**: + +* **Code contributed**: I coded almost 1.5k LoC (lines of code) which can be further seen in [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=theprevailingone). + +With every feature that I have implemented, I made sure to include the proper test to improve future extendability. + +* **Enhancements to existing features**: + * Allow sorting of entry lists to persist across sessions. + * Find and List Commands will have their display sorted if previously sorted by a Sort Command. + * Improve and adjust the error messages/ usage messages given by the commands. + +* **New Command Features**: + * Create the General Sort Command. + * Extending the General List Command, it will display the list of entries in a sorted manner. + * The Command accepts the paramater of search type and ordering. Search type dictates whether the entries displayed are archived, unarchived, or both. Ordering dictates the ordering of the entries, either ascending or descending. + * Create SortCommandParser to parse the Sort Command. + * A universal sort command parser that can be used to parse into all the sort commands. + * Extending ListCommandParser, it will parse the Sort Command (which inherits some of the List Command behaviour) and return the appropriate sort command. + * Create OrderingUtil and Ordering: + * OrderingUtil is a utility class that helps with converting a Comparator to its reverse or the other way depending on the Ordering. + * Ordering is an enum that contains the two possible values of the ordering (ascending and descending). + * Create Sort Company Command + * A feature that allows the user to sort the list of entries by company name. + * Create Sort Person Command + * A feature that allows the user to sort the list of entries by person name. + * Create Sort Event Command + * A feature that allows the user to sort the list of entries by event name. + +* **Team-based Tasks Contributions and Project Management**: + * Suggested the idea of Event to handle events relating to internships. + * Suggested the linking of Person and Event to Company. + * Help update the UI screenshots for UG and index.md + * Main handler of the User Guide. + +* **Review/mentoring contributions and Project Management**: + * Created 15 Pull Requests + * Helped reviewed 8 Pull Requests + * Provided 16 non trivial comments (as seen [here](https://nus-cs2103-ay2122s2.github.io/dashboards/contents/tp-comments.html)) + * Manage release for v1.4.0 + diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md index 880c701042f..f1a5377edd5 100644 --- a/docs/tutorials/AddRemark.md +++ b/docs/tutorials/AddRemark.md @@ -229,7 +229,7 @@ Now that we have all the information that we need, let’s lay the groundwork fo ### Add a new `Remark` class -Create a new `Remark` in `seedu.address.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code. +Create a new `Remark` in `seedu.address.model.entry`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code. A copy-paste and search-replace later, you should have something like [this](https://github.com/se-edu/addressbook-level3/commit/4516e099699baa9e2d51801bd26f016d812dedcc#diff-41bb13c581e280c686198251ad6cc337cd5e27032772f06ed9bf7f1440995ece). Note how `Remark` has no constrains and thus does not require input validation. diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md index f29169bc924..cdc6790b5c6 100644 --- a/docs/tutorials/RemovingFields.md +++ b/docs/tutorials/RemovingFields.md @@ -28,7 +28,7 @@ IntelliJ IDEA provides a refactoring tool that can identify *most* parts of a re ### Assisted refactoring -The `address` field in `Person` is actually an instance of the `seedu.address.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu. +The `address` field in `Person` is actually an instance of the `seedu.address.model.entry.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu. * :bulb: To make things simpler, you can unselect the options `Search in comments and strings` and `Search for text occurrences` ![Usages detected](../images/remove/UnsafeDelete.png) diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md index 4fb62a83ef6..9f8d365a840 100644 --- a/docs/tutorials/TracingCode.md +++ b/docs/tutorials/TracingCode.md @@ -191,7 +191,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [ ... Person personToEdit = lastShownList.get(index.getZeroBased()); Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { + if (!personToEdit.isSameEntry(editedPerson) && model.hasPerson(editedPerson)) { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } model.setPerson(personToEdit, editedPerson); diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 4133aaa0151..8c81ba20092 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -36,7 +36,7 @@ */ public class MainApp extends Application { - public static final Version VERSION = new Version(0, 2, 0, true); + public static final Version VERSION = new Version(1, 3, 0, true); private static final Logger logger = LogsCenter.getLogger(MainApp.class); diff --git a/src/main/java/seedu/address/commons/core/ListType.java b/src/main/java/seedu/address/commons/core/ListType.java new file mode 100644 index 00000000000..7ad9fa685b1 --- /dev/null +++ b/src/main/java/seedu/address/commons/core/ListType.java @@ -0,0 +1,7 @@ +package seedu.address.commons.core; + +public enum ListType { + PERSON, + COMPANY, + EVENT +} diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 1deb3a1e469..0301f9d5fb7 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -7,7 +7,10 @@ public class Messages { public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; + public static final String MESSAGE_INVALID_ENTRY_DISPLAYED_INDEX = "The entry index provided is invalid"; + public static final String MESSAGE_COMPANIES_LISTED_OVERVIEW = "%1$d companies listed!"; + public static final String MESSAGE_EVENTS_LISTED_OVERVIEW = "%1$d events listed!"; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - + public static final String MESSAGE_NONEXISTENT_COMPANY = "The company provided does not exist in the company list"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; } diff --git a/src/main/java/seedu/address/commons/core/OrderingUtil.java b/src/main/java/seedu/address/commons/core/OrderingUtil.java new file mode 100644 index 00000000000..07d0d080271 --- /dev/null +++ b/src/main/java/seedu/address/commons/core/OrderingUtil.java @@ -0,0 +1,25 @@ +package seedu.address.commons.core; + +import java.util.Comparator; + +import seedu.address.model.entry.Entry; + +public class OrderingUtil { + public static enum Ordering { + ASCENDING, DESCENDING + } + + /** + * Returns a comparator that compares {@code Entry}s based on the given {@code Ordering}. + */ + public static Comparator orderedComparator(Ordering ordering, Comparator comparator) { + switch (ordering) { + case ASCENDING: + return comparator; + case DESCENDING: + return comparator.reversed(); + default: + throw new IllegalArgumentException("Unknown ordering: " + ordering); + } + } +} diff --git a/src/main/java/seedu/address/commons/core/SearchTypeUtil.java b/src/main/java/seedu/address/commons/core/SearchTypeUtil.java new file mode 100644 index 00000000000..6c3ba12a7fa --- /dev/null +++ b/src/main/java/seedu/address/commons/core/SearchTypeUtil.java @@ -0,0 +1,25 @@ +package seedu.address.commons.core; + +import java.util.function.Predicate; + +import seedu.address.model.Model; +import seedu.address.model.entry.Entry; + +public class SearchTypeUtil { + public static enum SearchType { UNARCHIVED_ONLY, ARCHIVED_ONLY, ALL } + + public static Predicate getPredicate(SearchType searchType) { + switch (searchType) { + case UNARCHIVED_ONLY: + return Model.PREDICATE_SHOW_UNARCHIVED_ONLY; + case ARCHIVED_ONLY: + return Model.PREDICATE_SHOW_ARCHIVED_ONLY; + case ALL: + return Model.PREDICATE_SHOW_ALL; + default: + // should never reach here + } + + return null; + } +} diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 61cc8c9a1cb..9d491d08fef 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -65,4 +65,22 @@ public static boolean isNonZeroUnsignedInteger(String s) { return false; } } + + /** + * Returns true if {@code s} represents an integer + * e.g. {@code Long.MIN_VALUE}, ..., -2, -1, 0, 1, 2, ..., {@code Long.MAX_VALUE}
+ * Will return false for any other non-null string input + * e.g. empty string, "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters) + * @throws NullPointerException if {@code s} is null. + */ + public static boolean isLong(String s) { + requireNonNull(s); + + try { + Long.parseLong(s); + return true; + } catch (NumberFormatException nfe) { + return false; + } + } } diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 92cd8fa605a..29105cb5aff 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -8,7 +8,9 @@ import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import seedu.address.model.entry.Company; +import seedu.address.model.entry.Event; +import seedu.address.model.entry.Person; /** * API of the Logic component @@ -33,6 +35,12 @@ public interface Logic { /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of companies */ + ObservableList getFilteredCompanyList(); + + /** Returns an unmodifiable view of the filtered list of events */ + ObservableList getFilteredEventList(); + /** * Returns the user prefs' address book file path. */ @@ -47,4 +55,5 @@ public interface Logic { * Set the user prefs' GUI settings. */ void setGuiSettings(GuiSettings guiSettings); + } diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 9d9c6d15bdc..68738b15860 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -14,7 +14,9 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.Model; import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import seedu.address.model.entry.Company; +import seedu.address.model.entry.Event; +import seedu.address.model.entry.Person; import seedu.address.storage.Storage; /** @@ -64,6 +66,16 @@ public ObservableList getFilteredPersonList() { return model.getFilteredPersonList(); } + @Override + public ObservableList getFilteredCompanyList() { + return model.getFilteredCompanyList(); + } + + @Override + public ObservableList getFilteredEventList() { + return model.getFilteredEventList(); + } + @Override public Path getAddressBookFilePath() { return model.getAddressBookFilePath(); @@ -78,4 +90,5 @@ public GuiSettings getGuiSettings() { public void setGuiSettings(GuiSettings guiSettings) { model.setGuiSettings(guiSettings); } + } diff --git a/src/main/java/seedu/address/logic/commands/AddCompanyCommand.java b/src/main/java/seedu/address/logic/commands/AddCompanyCommand.java new file mode 100644 index 00000000000..0783348e602 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddCompanyCommand.java @@ -0,0 +1,66 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +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_TAG; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Company; + +/** + * Adds a company to the address book. + */ +public class AddCompanyCommand extends Command { + public static final String COMMAND_WORD = "addc"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a company to the list of companies.\n" + + "Parameters: " + + PREFIX_NAME + "NAME " + + PREFIX_PHONE + "PHONE " + + PREFIX_EMAIL + "EMAIL " + + PREFIX_ADDRESS + "ADDRESS " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_NAME + "Shopee " + + PREFIX_PHONE + "96613725 " + + PREFIX_EMAIL + "askhr@shopee.com " + + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + + PREFIX_TAG + "ecommerce " + + PREFIX_TAG + "hiring"; + + public static final String MESSAGE_SUCCESS = "New company added: %1$s"; + public static final String MESSAGE_DUPLICATE_COMPANY = "This company already exists in the list of companies."; + + private final Company toAdd; + + /** + * Creates an AddCompanyCommand to add the specified {@code Company} + */ + public AddCompanyCommand(Company company) { + requireNonNull(company); + toAdd = company; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasCompany(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_COMPANY); + } + + model.addCompany(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddCompanyCommand // instanceof handles nulls + && toAdd.equals(((AddCompanyCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddEventCommand.java b/src/main/java/seedu/address/logic/commands/AddEventCommand.java new file mode 100644 index 00000000000..cfc197f9fd9 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddEventCommand.java @@ -0,0 +1,75 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_NONEXISTENT_COMPANY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Event; + +/** + * Adds a person to the address book. + */ +public class AddEventCommand extends Command { + + public static final String COMMAND_WORD = "adde"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an event to the list of events.\n" + + "Parameters: " + + PREFIX_NAME + "NAME " + + PREFIX_COMPANY + "COMPANY_NAME " + + PREFIX_DATE + "DATE " + + PREFIX_TIME + "TIME " + + PREFIX_LOCATION + "LOCATION " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_NAME + "Interview " + + PREFIX_COMPANY + "ABC " + + PREFIX_DATE + "2022-10-31 " + + PREFIX_TIME + "13:30 " + + PREFIX_LOCATION + "zoom " + + PREFIX_TAG + "technical " + + PREFIX_TAG + "coding"; + + public static final String MESSAGE_SUCCESS = "New event added: %1$s"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists in the list of events."; + + private final Event toAdd; + + /** + * Creates an AddCommand to add the specified {@code Person} + */ + public AddEventCommand(Event event) { + requireNonNull(event); + toAdd = event; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (!model.hasCompany(toAdd.getCompanyName())) { + throw new CommandException(MESSAGE_NONEXISTENT_COMPANY); + } + + if (model.hasEvent(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_EVENT); + } + + model.addEvent(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddEventCommand // instanceof handles nulls + && toAdd.equals(((AddEventCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddPersonCommand.java similarity index 66% rename from src/main/java/seedu/address/logic/commands/AddCommand.java rename to src/main/java/seedu/address/logic/commands/AddPersonCommand.java index 71656d7c5c8..95fceeef4e2 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddPersonCommand.java @@ -1,7 +1,8 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.commons.core.Messages.MESSAGE_NONEXISTENT_COMPANY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; @@ -9,39 +10,39 @@ import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.entry.Person; /** * Adds a person to the address book. */ -public class AddCommand extends Command { +public class AddPersonCommand extends Command { - public static final String COMMAND_WORD = "add"; + public static final String COMMAND_WORD = "addp"; - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. " + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the list of persons.\n" + "Parameters: " + PREFIX_NAME + "NAME " + + PREFIX_COMPANY + "COMPANY_NAME " + PREFIX_PHONE + "PHONE " + PREFIX_EMAIL + "EMAIL " - + PREFIX_ADDRESS + "ADDRESS " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + + PREFIX_COMPANY + "ABC " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " - + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + PREFIX_TAG + "friends " + PREFIX_TAG + "owesMoney"; public static final String MESSAGE_SUCCESS = "New person added: %1$s"; - public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the list of persons."; private final Person toAdd; /** - * Creates an AddCommand to add the specified {@code Person} + * Creates an AddPersonCommand to add the specified {@code Person} */ - public AddCommand(Person person) { + public AddPersonCommand(Person person) { requireNonNull(person); toAdd = person; } @@ -50,6 +51,10 @@ public AddCommand(Person person) { public CommandResult execute(Model model) throws CommandException { requireNonNull(model); + if (!model.hasCompany(toAdd.getCompanyName())) { + throw new CommandException(MESSAGE_NONEXISTENT_COMPANY); + } + if (model.hasPerson(toAdd)) { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } @@ -61,7 +66,7 @@ public CommandResult execute(Model model) throws CommandException { @Override public boolean equals(Object other) { return other == this // short circuit if same object - || (other instanceof AddCommand // instanceof handles nulls - && toAdd.equals(((AddCommand) other).toAdd)); + || (other instanceof AddPersonCommand // instanceof handles nulls + && toAdd.equals(((AddPersonCommand) other).toAdd)); } } diff --git a/src/main/java/seedu/address/logic/commands/ArchiveAllCommand.java b/src/main/java/seedu/address/logic/commands/ArchiveAllCommand.java new file mode 100644 index 00000000000..4cb65243a83 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ArchiveAllCommand.java @@ -0,0 +1,42 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL; +import static seedu.address.model.Model.PREDICATE_SHOW_ARCHIVED_ONLY; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Entry; + +public class ArchiveAllCommand extends Command { + public static final String COMMAND_WORD = "archive_all"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Archives all entries in the displayed entry list."; + + public static final String MESSAGE_SUCCESS = "Archived all entries"; + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + Entry archivedEntry = model.archiveEntry(0, true); + + for (int index = 1; archivedEntry != null; index++) { + archivedEntry = model.archiveEntry(index, true); + } + + // If the filteredList's predicate is UNARCHIVED_ONLY it will not update itself to remove the archived + // entry, so we have to set it to a different predicate first. + model.updateCurrentlyDisplayedList(PREDICATE_SHOW_ALL); + model.updateCurrentlyDisplayedList(PREDICATE_SHOW_ARCHIVED_ONLY); + + return new CommandResult(MESSAGE_SUCCESS); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || other instanceof ArchiveCommand; // instanceof handles nulls + } +} diff --git a/src/main/java/seedu/address/logic/commands/ArchiveCommand.java b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java new file mode 100644 index 00000000000..954d66a60a5 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java @@ -0,0 +1,53 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL; +import static seedu.address.model.Model.PREDICATE_SHOW_UNARCHIVED_ONLY; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Entry; + +public class ArchiveCommand extends Command { + public static final String COMMAND_WORD = "archive"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Archives the entry identified by the index number used in the displayed entry list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_ARCHIVE_ENTRY_SUCCESS = "Archived Entry: %1$s"; + + private final Index targetIndex; + + public ArchiveCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + Entry archivedEntry = model.archiveEntry(targetIndex.getZeroBased(), true); + + if (archivedEntry == null) { + throw new CommandException(Messages.MESSAGE_INVALID_ENTRY_DISPLAYED_INDEX); + } + + // If the filteredList's predicate is UNARCHIVED_ONLY it will not update itself to remove the archived + // entry, so we have to set it to a different predicate first. + model.updateCurrentlyDisplayedList(PREDICATE_SHOW_ALL); + model.updateCurrentlyDisplayedList(PREDICATE_SHOW_UNARCHIVED_ONLY); + + return new CommandResult(String.format(MESSAGE_ARCHIVE_ENTRY_SUCCESS, archivedEntry)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ArchiveCommand // instanceof handles nulls + && targetIndex.equals(((ArchiveCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java index 9c86b1fa6e4..666b9bc6b8f 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java @@ -11,7 +11,7 @@ public class ClearCommand extends Command { public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; + public static final String MESSAGE_SUCCESS = "All lists have been cleared!"; @Override diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java index 92f900b7916..fb14ebb672e 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/address/logic/commands/CommandResult.java @@ -17,13 +17,26 @@ public class CommandResult { /** The application should exit. */ private final boolean exit; + /** The application should change the display to show only the person list. */ + private final boolean showPerson; + + /** The application should change the display to show only the company list. */ + private final boolean showCompany; + + /** The application should change the display to show only the event list. */ + private final boolean showEvent; + /** * Constructs a {@code CommandResult} with the specified fields. */ - public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, + boolean showPerson, boolean showCompany, boolean showEvent) { this.feedbackToUser = requireNonNull(feedbackToUser); this.showHelp = showHelp; this.exit = exit; + this.showPerson = showPerson; + this.showCompany = showCompany; + this.showEvent = showEvent; } /** @@ -31,7 +44,7 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { * and other fields set to their default value. */ public CommandResult(String feedbackToUser) { - this(feedbackToUser, false, false); + this(feedbackToUser, false, false, false, false, false); } public String getFeedbackToUser() { @@ -46,6 +59,18 @@ public boolean isExit() { return exit; } + public boolean isShowPerson() { + return showPerson; + } + + public boolean isShowCompany() { + return showCompany; + } + + public boolean isShowEvent() { + return showEvent; + } + @Override public boolean equals(Object other) { if (other == this) { @@ -60,12 +85,15 @@ public boolean equals(Object other) { CommandResult otherCommandResult = (CommandResult) other; return feedbackToUser.equals(otherCommandResult.feedbackToUser) && showHelp == otherCommandResult.showHelp - && exit == otherCommandResult.exit; + && exit == otherCommandResult.exit + && showPerson == otherCommandResult.showPerson + && showCompany == otherCommandResult.showCompany + && showEvent == otherCommandResult.showEvent; } @Override public int hashCode() { - return Objects.hash(feedbackToUser, showHelp, exit); + return Objects.hash(feedbackToUser, showHelp, exit, showPerson, showCompany, showEvent); } } diff --git a/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java b/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java new file mode 100644 index 00000000000..01cd106e6ec --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java @@ -0,0 +1,34 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.address.model.Model; +import seedu.address.model.entry.Entry; + +public class DeleteAllCommand extends Command { + public static final String COMMAND_WORD = "delete_all"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes all entries in the displayed entry list."; + + public static final String MESSAGE_SUCCESS = "Deleted all entries."; + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + + Entry deletedEntry = model.deleteEntry(0); + + while (deletedEntry != null) { + deletedEntry = model.deleteEntry(0); + } + + return new CommandResult(MESSAGE_SUCCESS); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || other instanceof DeleteCommand; // instanceof handles nulls + } +} diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java index 02fd256acba..919c1c20e92 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java @@ -2,27 +2,25 @@ import static java.util.Objects.requireNonNull; -import java.util.List; - import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.entry.Entry; /** - * Deletes a person identified using it's displayed index from the address book. + * Deletes an entry identified using its displayed index from the address book. */ public class DeleteCommand extends Command { public static final String COMMAND_WORD = "delete"; public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the displayed person list.\n" + + ": Deletes the entry identified by the index number used in the displayed entry list.\n" + "Parameters: INDEX (must be a positive integer)\n" + "Example: " + COMMAND_WORD + " 1"; - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; + public static final String MESSAGE_DELETE_ENTRY_SUCCESS = "Deleted Entry: %1$s"; private final Index targetIndex; @@ -33,15 +31,14 @@ public DeleteCommand(Index targetIndex) { @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - if (targetIndex.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + Entry deletedEntry = model.deleteEntry(targetIndex.getZeroBased()); + + if (deletedEntry == null) { + throw new CommandException(Messages.MESSAGE_INVALID_ENTRY_DISPLAYED_INDEX); } - Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); - model.deletePerson(personToDelete); - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + return new CommandResult(String.format(MESSAGE_DELETE_ENTRY_SUCCESS, deletedEntry)); } @Override diff --git a/src/main/java/seedu/address/logic/commands/EditCompanyCommand.java b/src/main/java/seedu/address/logic/commands/EditCompanyCommand.java new file mode 100644 index 00000000000..8ca0280e916 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditCompanyCommand.java @@ -0,0 +1,231 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +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_TAG; +import static seedu.address.model.Model.PREDICATE_SHOW_UNARCHIVED_ONLY; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Address; +import seedu.address.model.entry.Company; +import seedu.address.model.entry.Email; +import seedu.address.model.entry.Name; +import seedu.address.model.entry.Phone; +import seedu.address.model.tag.Tag; + +/** + * Edits the details of an existing company in the address book. + */ +public class EditCompanyCommand extends Command { + + public static final String COMMAND_WORD = "editc"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the company identified " + + "by the index number used in the displayed company list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_PHONE + "PHONE] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_ADDRESS + "ADDRESS] " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_PHONE + "91234567 " + + PREFIX_EMAIL + "johndoe@example.com"; + + public static final String MESSAGE_EDIT_COMPANY_SUCCESS = "Edited Company: %1$s"; + public static final String MESSAGE_DUPLICATE_COMPANY = "This company already exists in the list of companies."; + + private final Index index; + private final EditCompanyDescriptor editCompanyDescriptor; + + /** + * @param index of the company in the filtered company list to edit + * @param editCompanyDescriptor details to edit the company with + */ + public EditCompanyCommand(Index index, EditCompanyDescriptor editCompanyDescriptor) { + requireNonNull(index); + requireNonNull(editCompanyDescriptor); + + this.index = index; + this.editCompanyDescriptor = new EditCompanyDescriptor(editCompanyDescriptor); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredCompanyList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_ENTRY_DISPLAYED_INDEX); + } + + Company companyToEdit = lastShownList.get(index.getZeroBased()); + Company editedCompany = createEditedCompany(companyToEdit, editCompanyDescriptor); + + if (!companyToEdit.isSameEntry(editedCompany) && model.hasCompany(editedCompany)) { + throw new CommandException(MESSAGE_DUPLICATE_COMPANY); + } + + model.setCompany(companyToEdit, editedCompany); + model.showCompanyList(PREDICATE_SHOW_UNARCHIVED_ONLY); + + if (!companyToEdit.getName().equals(editedCompany.getName())) { + model.getAddressBook().updateCompanyNames( + companyToEdit.getName().toString(), editedCompany.getName().toString()); + } + + return new CommandResult(String.format(MESSAGE_EDIT_COMPANY_SUCCESS, editedCompany)); + } + + /** + * Creates and returns a {@code Company} with the details of {@code companyToEdit} + * edited with {@code editCompanyDescriptor}. + */ + private static Company createEditedCompany(Company companyToEdit, EditCompanyDescriptor editCompanyDescriptor) { + assert companyToEdit != null; + + Name updatedName = editCompanyDescriptor.getName().orElse(companyToEdit.getName()); + Phone updatedPhone = editCompanyDescriptor.getPhone().orElse(companyToEdit.getPhone()); + Email updatedEmail = editCompanyDescriptor.getEmail().orElse(companyToEdit.getEmail()); + Address updatedAddress = editCompanyDescriptor.getAddress().orElse(companyToEdit.getAddress()); + Set updatedTags = editCompanyDescriptor.getTags().orElse(companyToEdit.getTags()); + + return new Company(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditCompanyCommand)) { + return false; + } + + // state check + EditCompanyCommand e = (EditCompanyCommand) other; + return index.equals(e.index) + && editCompanyDescriptor.equals(e.editCompanyDescriptor); + } + + /** + * Stores the details to edit the company with. Each non-empty field value will replace the + * corresponding field value of the company. + */ + public static class EditCompanyDescriptor { + private Name name; + private Phone phone; + private Email email; + private Address address; + private Set tags; + + public EditCompanyDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditCompanyDescriptor(EditCompanyDescriptor toCopy) { + setName(toCopy.name); + setPhone(toCopy.phone); + setEmail(toCopy.email); + setTags(toCopy.tags); + setAddress(toCopy.address); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); + } + + public void setName(Name name) { + this.name = name; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public void setPhone(Phone phone) { + this.phone = phone; + } + + public Optional getPhone() { + return Optional.ofNullable(phone); + } + + public void setEmail(Email email) { + this.email = email; + } + + public Optional getEmail() { + return Optional.ofNullable(email); + } + + public void setAddress(Address address) { + this.address = address; + } + + public Optional
getAddress() { + return Optional.ofNullable(address); + } + + /** + * Sets {@code tags} to this object's {@code tags}. + * A defensive copy of {@code tags} is used internally. + */ + public void setTags(Set tags) { + this.tags = (tags != null) ? new HashSet<>(tags) : null; + } + + /** + * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + * Returns {@code Optional#empty()} if {@code tags} is null. + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditCompanyDescriptor)) { + return false; + } + + // state check + EditCompanyDescriptor e = (EditCompanyDescriptor) other; + + return getName().equals(e.getName()) + && getPhone().equals(e.getPhone()) + && getEmail().equals(e.getEmail()) + && getAddress().equals(e.getAddress()) + && getTags().equals(e.getTags()); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/EditEventCommand.java b/src/main/java/seedu/address/logic/commands/EditEventCommand.java new file mode 100644 index 00000000000..dee55ae5b16 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditEventCommand.java @@ -0,0 +1,245 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_NONEXISTENT_COMPANY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME; +import static seedu.address.model.Model.PREDICATE_SHOW_UNARCHIVED_ONLY; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.entry.Date; +import seedu.address.model.entry.Event; +import seedu.address.model.entry.Location; +import seedu.address.model.entry.Name; +import seedu.address.model.entry.Time; +import seedu.address.model.tag.Tag; + +/** + * Edits the details of an existing event in the address book. + */ +public class EditEventCommand extends Command { + public static final String COMMAND_WORD = "edite"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the event identified " + + "by the index number used in the displayed event list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_COMPANY + "COMPANY_NAME] " + + "[" + PREFIX_DATE + "DATE] " + + "[" + PREFIX_TIME + "TIME] " + + "[" + PREFIX_LOCATION + "LOCATION] " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_DATE + "2022-04-20 " + + PREFIX_TIME + "12:20"; + + public static final String MESSAGE_EDIT_EVENT_SUCCESS = "Edited Event: %1$s"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists in the list of events."; + + private final Index index; + private final EditEventCommand.EditEventDescriptor editEventDescriptor; + + /** + * @param index of the event in the filtered event list to edit + * @param editEventDescriptor details to edit the event with + */ + public EditEventCommand(Index index, EditEventCommand.EditEventDescriptor editEventDescriptor) { + requireNonNull(index); + requireNonNull(editEventDescriptor); + + this.index = index; + this.editEventDescriptor = new EditEventCommand.EditEventDescriptor(editEventDescriptor); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredEventList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_ENTRY_DISPLAYED_INDEX); + } + + Event eventToEdit = lastShownList.get(index.getZeroBased()); + Event editedEvent = createEditedEvent(eventToEdit, editEventDescriptor); + + if (!eventToEdit.isSameEntry(editedEvent) && model.hasEvent(editedEvent)) { + throw new CommandException(MESSAGE_DUPLICATE_EVENT); + } + + if (!model.hasCompany(editedEvent.getCompanyName())) { + throw new CommandException(MESSAGE_NONEXISTENT_COMPANY); + } + + model.setEvent(eventToEdit, editedEvent); + model.showEventList(PREDICATE_SHOW_UNARCHIVED_ONLY); + return new CommandResult(String.format(MESSAGE_EDIT_EVENT_SUCCESS, editedEvent)); + } + + /** + * Creates and returns a {@code Event} with the details of {@code eventToEdit} + * edited with {@code editEventDescriptor}. + */ + private static Event createEditedEvent(Event eventToEdit, EditEventDescriptor editEventDescriptor) { + assert eventToEdit != null; + + Name updatedName = editEventDescriptor.getName().orElse(eventToEdit.getName()); + Name updatedCompanyName = editEventDescriptor.getCompanyName().orElse(eventToEdit.getCompanyName()); + Date updatedDate = editEventDescriptor.getDate().orElse(eventToEdit.getDate()); + Time updatedTime = editEventDescriptor.getTime().orElse(eventToEdit.getTime()); + Location updatedLocation = editEventDescriptor.getLocation().orElse(eventToEdit.getLocation()); + Set updatedTags = editEventDescriptor.getTags().orElse(eventToEdit.getTags()); + + return new Event(updatedName, updatedCompanyName, updatedDate, updatedTime, updatedLocation, updatedTags); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditEventCommand)) { + return false; + } + + // state check + EditEventCommand e = (EditEventCommand) other; + return index.equals(e.index) + && editEventDescriptor.equals(e.editEventDescriptor); + } + + /** + * Stores the details to edit the event with. Each non-empty field value will replace the + * corresponding field value of the event. + */ + public static class EditEventDescriptor { + private Name name; + private Name companyName; + private Date date; + private Time time; + private Location location; + private Set tags; + + public EditEventDescriptor() { + } + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditEventDescriptor(EditEventCommand.EditEventDescriptor toCopy) { + setName(toCopy.name); + setCompanyName(toCopy.companyName); + setDate(toCopy.date); + setTime(toCopy.time); + setLocation(toCopy.location); + setTags(toCopy.tags); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, companyName, date, time, location, tags); + } + + public void setName(Name name) { + this.name = name; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public void setCompanyName(Name companyName) { + this.companyName = companyName; + } + + public Optional getCompanyName() { + return Optional.ofNullable(companyName); + } + + public void setDate(Date date) { + this.date = date; + } + + public Optional getDate() { + return Optional.ofNullable(date); + } + + public void setTime(Time time) { + this.time = time; + } + + public Optional