diff --git a/README.md b/README.md
index 13f5c77403f..62a66080735 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,17 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+[](https://github.com/se-edu/addressbook-level3/actions) [](https://codecov.io/gh/AY2324S2-CS2103T-T08-3/tp)

-* This is **a sample project for Software Engineering (SE) students**.
+* This is **a project for Computer professional job seekers**.
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.
+ * as a tool to manage job applications
+ * as a tool to manage contacts of recruiters and interviewers
+* The project simulates an ongoing software project for a desktop application (called _CareerConnect Bot_) 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` ...).
+* It is named `CareerConnect Bot` (`CCBot` for short), 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.
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+
+
+
diff --git a/build.gradle b/build.gradle
index a2951cc709e..4e1ce7b9c71 100644
--- a/build.gradle
+++ b/build.gradle
@@ -66,7 +66,11 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'CCBOT.jar'
+}
+
+run {
+ enableAssertions = true
}
defaultTasks 'clean', 'test'
diff --git a/docs/.Rhistory b/docs/.Rhistory
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..851ba29c3f6 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,50 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Zhang Tianyao
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[homepage](https://github.com/ZHANGTIANYAO1)]
+[[github](https://github.com/ZHANGTIANYAO1)]
+[[portfolio](team/zhangtianyao1.md)]
* Role: Project Advisor
-### Jane Doe
+### Mahathir Norrahim
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/dabzpengu)]
* Role: Team Lead
-* Responsibilities: UI
+* Responsibilities: UI / Quality Assurance
-### Johnny Doe
+### Tan Yi Jing
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/Lalelulilulela)] [[portfolio](team/lalelulilulela.md)]
* Role: Developer
* Responsibilities: Data
-### Jean Doe
+### Ashley Chua Xin Ru
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/ashleyy2444)]
+[[portfolio](team/ashley.md)]
* Role: Developer
* Responsibilities: Dev Ops + Threading
-### James Doe
+### Dexter Wong
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/Dexter-Wong)]
+[[portfolio](team/dexter.md)]
* Role: Developer
* Responsibilities: UI
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 1b56bb5d31b..7b7fa1b5af9 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -70,7 +70,7 @@ The sections below give more details of each 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 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.
@@ -155,178 +155,349 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Sorting Contact List
+
+#### Overview of SortCommand
+This feature allows users to sort their addressbook based on various information, namely name, company
+name, interview time, salary and priority. This feature leverages on the built-in `ObservableList` provided by JavaFX.
+The sorting is done by creating classes that implements the Comparator interface.
+
+#### Comparator Classes
+* `PersonCompanyNameComparator.java`
+* `PersonInterviewTimeComparator.java`
+* `PersonNameComparator.java`
+* `PersonPriorityComparator.java`
+* `PersonSalaryComparator.java`
+
+These comparators are referenced in the `SortCommandParser`. In the `SortCommandParser` each comparator will be assigned
+a static integer based on the CLI Syntax from the userInput. The string is that parsed and assigned an integer from
+**1 - 4** which are pre-assigned to a comparator.
+
+
+
+**Process**:
+1. User inputs `sort pri/`, triggering the `execute()` function in the `LogicManager` object.
+ - `pri/` is a CLI syntax added to refer to priority, an attribute added to the `Person` class.
+2. `LogicManager` invokes the `parseCommand()` function in the `AddressBookParser`, which interprets the
+ `sort` command and creates a `SortCommandParser` object.
+3. The `SortCommandParser` parses `pri/` and creates the `SortCommand` object.
+ - The `SortCommand` constructor accepts an **Integer**, with `SortCommandParser` pre-assigning `pri/` to 0.
+4. `LogicManager` executes the command.
+5. `SortCommand` calls `updateSortedPersonList()` from the `Model` object, which references the
+ `AddressBook` containing the `UniquePersonList`. The `UniquePersonList` sorts based on the assigned comparator.
+
+#### Class Structure
+- `SortCommand` class: Responsible for executing the sort operation based on the specified attribute. Inherits from the
+ `Command` class and utilizes multiple comparator classes to sort contacts based on various attributes.
+
+#### Method Details
+- `SortCommand(Integer info, boolean isInverse)`: Constructor that takes an integer representing the attribute index
+ and a boolean indicating whether to sort in reverse order.
+- `execute(Model model)`: Executes the command to sort the list of contacts in the address book based on the specified
+ attribute. Utilises switch-case statements to select the appropriate comparator and sorts the contacts accordingly.
+- `equals(Object other)`: Overrides the equals method to compare if two `SortCommand` objects are equal based on the
+ attribute index.
+
+### Job Difficulty Feature
+
+
+#### Overview of Job Difficulty Feature
+The job difficulty feature calculates a difficulty score for a job based on the company name and salary. It utilises
+the local storage of renowned company names and their job difficulty levels.
+
+#### Class Structure
+- `JobDifficulty` class: Responsible for computing the job difficulty score. Utilizes `CompanyName` and `Salary`
+ classes to fetch the necessary information.
+
+#### Method Details
+- `JobDifficulty(CompanyName companyName, Salary salary)`: Constructor that takes a `CompanyName` object and a `Salary`
+ object to compute the job difficulty score.
+- `getDifficulty()`: Returns the calculated job difficulty score.
+
+### Filtering of List Feature
+
+#### Overview of Filtering List Feature
+This feature allows users to filter their lists according to the interview time range, tags, salary range
+and programming language.
+
+#### Implementation
+- `FilterCommand` class: An abstract class inherited by concrete classes, such as `FilterInterviewTimeCommand`,
+ `FilterTagCommand`, `FilterSalaryCommand`, and `FilterProgrammingLanguageCommand`. These classes filter the list
+ according to their respective categories.
+
+**Process:**
+1. `FilterCommandParser` determines a concrete subclass of `FilterCommand` to return.
+2. The concrete `FilterCommandClass` checks if their respective categories (interview times, tags, etc.) in the contact list contain the keyword.
+3. Returns the list of contacts containing the keyword.
+
+### Deleting Contacts With Same Tag Feature
+
+
+#### Overview of DeletingTagCommand
+The `DeleteTagCommand` feature enables users to delete all contacts associated with a specified tag from the address
+book. This feature uses the `TagContainsKeywordsPredicate` class to filter and identify contacts with the specified tag for deletion.
+
+**Process**:
+1. `DeleteTagCommandParser` determines a concrete subclass of `DeleteTagCommand` to return.
+2. The concrete `DeleteTagCommand` class retrieves the list of tags to be deleted from the
+ `TagContainsKeywordsPredicate`.
+4. Filters the contacts in the address book based on these tags.
+5. Deletes the filtered contacts from the address book model.
+
+#### Class Structure
+- `DeleteTagCommand` class: Responsible for executing the delete operation based on the specified tag. Inherits from
+ the `DeleteAbstractCommand` class and utilizes the `TagContainsKeywordsPredicate` class to filter contacts.
+
+#### Method Details
+- `DeleteTagCommand(TagContainsKeywordsPredicate tagToDelete)`: Constructor that takes a `TagContainsKeywordsPredicate`
+ object representing the tag to be deleted.
+- `execute(Model model)`: Executes the command to delete all contacts with the specified tag from the address book.
+ Retrieves the list of tags to be deleted, filters the contacts based on these tags, and deletes them from the model.
+
+### Finding Contact Name by Company Name Feature
+
+#### Overview of FindCommand
+The `FindCommand` feature allows users to search and list all persons in the address book whose name or company name
+contains any of the specified keywords. This feature employs the `NameOrCompanyNameContainsKeywordsPredicate` class to
+filter and identify contacts based on their names or company names.
+
+**Process**:
+1. `FindCommandParser` determines a concrete subclass of `FindCommand` to return.
+2. The concrete `FindCommand` class checks if the names or company names of contacts in the address book contain the
+specified keywords.
+3. It returns the list of contacts whose names or company names contain the keyword.
+
+#### Class Structure
+- `FindCommand` class: Responsible for executing the find operation based on the specified keywords. Inherits from the
+ `Command` class and utilizes the `NameOrCompanyNameContainsKeywordsPredicate` class to filter contacts.
+
+#### Method Details
+- `FindCommand(NameOrCompanyNameContainsKeywordsPredicate predicate)`: Constructor that takes a
+ `NameOrCompanyNameContainsKeywordsPredicate` object representing the keywords to search for.
+- `execute(Model model)`: Executes the command to find and list all contacts whose names or company names contain the
+ specified keywords. Retrieves the list of contacts matching the predicate, updates the filtered contact list in the
+ model, and returns a command result indicating the number of contacts found.
+
+### Add resume feature
+
+The add resume feature allows user to add their own personal and professional details that would be required in a
+job search. This feature has its own UI, similar to the `Help` feature.
+
+#### Implementation
+This feature introduces a new `User` **singleton** class. The structure is as shown below.
+
+The `ResumeWindow` controller, that controls the FXML file that displays the resume, has a reference to the
+User class to retrieve the values of the user, if any.
+
+#### Process:
+1. User inputs `resume...` into UI.
+2. The `UIManager` then calls `LogicManager`
+3. `AddressBookParser` is called.
+4. `AddressBookParser` resets the User's attributes and re-assigns them to the current inputs
+5. `AddResumeCommand` is instantiated and its `execute()` is called to return `CommandResult`
+6. `ResumeWindow` is opened or reopened to show the current values.
+--------------------------------------------------------------------------------------------------------------------
-#### Proposed Implementation
+## **Documentation, logging, testing, configuration, dev-ops**
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+* [Documentation guide](Documentation.md)
+* [Testing guide](Testing.md)
+* [Logging guide](Logging.md)
+* [Configuration guide](Configuration.md)
+* [DevOps guide](DevOps.md)
-* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
-* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
-* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history.
+--------------------------------------------------------------------------------------------------------------------
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+## **Appendix: Requirements**
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+### Product scope
-Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
+**Target user profile**:
-
+* computing professionals looking for job openings
+* has a need to manage a significant number of company contacts
+* prefer desktop apps over other types
+* can type fast
+* prefers typing to mouse interactions
+* is reasonably comfortable using CLI apps
-Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
+**Value proposition**: User will be able to manage and schedule interview contacts, timings and job listings from a
+centralised location. Also manage contacts faster than a typical mouse/GUI driven app
-
-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`.
+### User stories
-
+Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
+| Priority | As a … | I want to … | So that I can… |
+|----------|-----------------------------|--------------------------------------------------|--------------------------------------------------------------------|
+| `* * *` | Computer science job seeker | delete features | delete information where necessary |
+| `* * *` | Computer science job seeker | add contact information of interviewer / company | contact the interviewer / company |
+| `* * *` | Computer science job seeker | add salary range | check the salary range of the job |
+| `* * *` | Computer science job seeker | add company name | check which company the job is from |
+| `* * *` | Computer science job seeker | add extra info about the company | recall the extra information about each of the companies | |
+| `* * *` | Computer science job seeker | add interview time | check what is the interview time |
+| `* *` | Computer science job seeker | add programming language(s) related to the job | identify which programming language(s) is/are required for the job |
+| `* *` | Computer science job seeker | add job responsibilities | check what are the job responsibilities for the job |
+| `* *` | Computer science job seeker | categorise job postings according to industry | filter information based on the different types of industries |
+| `*` | Computer science job seeker | receive notifications when I get a new interview | stay up-to-date with the interview offers and attend them |
+| `*` | Computer science job seeker | track the status of my job application | follow up with any actions when necessary |
+| `*` | Computer science job seeker | receive reminders for my interview timings | be reminded about the interview |
-
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
+### Use cases
-
+(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
-
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
-than attempting to perform the undo.
+---
-
+**Use case: Delete a person**
-The following sequence diagram shows how an undo operation goes through the `Logic` component:
+**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
-
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+ Use case ends.
-
+**Extensions**
-Similarly, how an undo operation goes through the `Model` component is shown below:
+* 2a. The list is empty.
-
+ Use case ends.
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
+* 3a. The given index is invalid.
-
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+ * 3a1. AddressBook shows an error message.
-
+ Use case resumes at step 2.
-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 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.
+**Use case: Add a Contact with Detailed Information**
-
+**MSS**
-The following activity diagram summarizes what happens when a user executes a new command:
+1. The user decides to add a new contact to their address book.
+2. The user inputs the add command followed by the contact's details in the format: add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]….
+3. CCBot validates the input details.
+4. CCBot adds the new contact to the address book, assigning it a unique identifier within the system.
+5. CCBot displays a confirmation message to the user indicating the successful addition of the new contact.
-
+ Use case ends.
-#### Design considerations:
+**Extensions**
-**Aspect: How undo & redo executes:**
+* 3a. If the user enters invalid details (e.g., incorrect format, missing mandatory fields like name or phone number):
+ * 3a1. CCBot shows an error message indicating the validation failure and the correct format of the command.
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+ Use case resumes at step 2.
+*a. At any time, User chooses to cancel the addition.
+ *a1. CCBot requests to confirm cancellation
+ *a2. User confirms the cancellation
+ Use case ends.
+---
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
+**Use case: Add Salary Range to a Contact**
-_{more aspects and alternatives to be added}_
+**MSS**
-### \[Proposed\] Data archiving
+1. The user decides to add a new contact with the salary or salary range info to their address book.
+2. User inputs the 'add' command with the salary detail in the correct format.
+3. CCBot validates the salary format and range.
+4. CCBot adds or updates the salary information for the contact and displays a success message.
-_{Explain here how the data archiving feature will be implemented}_
+ Use case ends.
+**Extensions**
---------------------------------------------------------------------------------------------------------------------
+* 3a. If the salary detail is invalid:
+ * 3a1. CCBot shows an error message indicating the validation failure and the correct format of the command.
-## **Documentation, logging, testing, configuration, dev-ops**
+ Use case resumes at step 2.
-* [Documentation guide](Documentation.md)
-* [Testing guide](Testing.md)
-* [Logging guide](Logging.md)
-* [Configuration guide](Configuration.md)
-* [DevOps guide](DevOps.md)
+---
---------------------------------------------------------------------------------------------------------------------
+**Use case: Add the Company’s Name to a Contact**
-## **Appendix: Requirements**
+**MSS**
-### Product scope
+1. The user decides to add a new contact with the company’s name info to their address book.
+2. User inputs the 'add' command with the company’s name in the correct format.
+3. CCBot validates the salary format and range.
+4. CCBot adds or updates the company’s name information for the contact and displays a success message.
-**Target user profile**:
+ Use case ends.
-* 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
+**Extensions**
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+* 3a. If the company’s name is bigger than 100 characters:
+ * 3a1. CCBot shows an error message indicating the validation failure and the limit characters number.
+ Use case resumes at step 2.
-### User stories
+---
-Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
+**Use case: Add Programming Language to a Contact**
-| 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 |
+**MSS**
-*{More to be added}*
+1. The user decides to add a new contact with the programming language info to their address book.
+2. User inputs the 'add' command with the programming language detail in the correct format.
+3. CCBot validates the salary format and range.
+4. CCBot adds or updates the programming language information for the contact and displays a success message.
-### Use cases
+ Use case ends.
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+**Extensions**
-**Use case: Delete a person**
+* 3a. If the programming language detail is invalid:
+ * 3a1. CCBot shows an error message indicating the validation failure and an error message about the format or character limit.
-**MSS**
+ Use case resumes at step 2.
-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
+---
- Use case ends.
+**Use case: Add extra info about the company to a Contact**
-**Extensions**
+**MSS**
-* 2a. The list is empty.
+1. The user decides to add a new contact with extra company info to their address book.
+2. User inputs the 'add' command with the extra information detail in the correct format.
+3. CCBot validates the input details.
+4. CCBot adds or updates the extra information for the contact and displays a success message.
- Use case ends.
+ Use case ends.
-* 3a. The given index is invalid.
+**Extensions**
- * 3a1. AddressBook shows an error message.
+* 3a. If the extra information detail is invalid:
+ * 3a1. CCBot shows an error message indicating the validation failure and an error message about the format or character limit.
Use case resumes at step 2.
-*{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 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.
+4. User Interface should be intuitive enough for users to easily add interview dates and salaries.
+5. System should be able to cater to various date formats given by users.
+6. System should be able to handle a minimum of 100 contacts
*{More to be added}*
### Glossary
+* **Computer Science job seeker** : Student / Unemployed / Working adult seeking employment opportunities in the field of Computer Science
* **Mainstream OS**: Windows, Linux, Unix, MacOS
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Private contact detail**: A contact detail that is not meant to be shared with others
--------------------------------------------------------------------------------------------------------------------
@@ -380,3 +551,75 @@ testers are expected to do more *exploratory* testing.
1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
1. _{ more test cases … }_
+--------------------------------------------------------------------------------------------------------------------
+## **Appendix: Planned Enhancements**
+
+Team size: 5
+1. **Have an error message show up when the data file is corrupted on startup**: The current address book simply starts
+up with an empty list when the data in the json file is corrupted or has an invalid format. The current implementation
+has a logger warning shown in the developer console, but not the app itself. We plan have an error message show up on
+results display after startup of the app when the data is corrupted.
+
+2. **Allow `filter` command to filter the contact list based on a combination of categories**: The current `filter`
+command only allows the contact list to be filtered based on one specific category such as tags, salary range etc
+and this may not be useful for users with a very huge number of contacts as filtering by only one category may still
+return a long list. It is also not convenient for users who want to find contacts more specifically. We plan to
+allow `filter` to filter the contact list more specifically. (e.g. `filter t/TAG s/SALARY_RANGE` will return
+contacts with matching `TAG` and `SALARY_RANGE` that falls within what is specified)
+
+3. **Show more specific error messages for our features**: The current `add`, `edit`, `resume`,
+`filter`, `find`, `sort`, and `delete` command requires prefixes such as `t/` and `s/` as their parameters. This may
+be confusing for users as they may input the wrong prefix for a command (e.g. input `edu/` in `add` command
+instead of in the `resume`command). We plan to allow the error message to throw more specific errors: `Invalid
+Command Format! edu/ is part of the resume command and not the add command.`
+
+4. **Improve help command functionality by making it easier for CLI users**:
+Makes it so that the `help` command bring up a tab with the link to the user guide automatically highlighted.
+This allows the user to simply use the keyboard shortcut `ctrl-c` to copy the link to their clipboard, instead of
+having to use the mouse to click the copy button manually. This allows users using the CLI to use the app more
+effectively.
+
+5. **Allow `add` command to add contacts with the same name**: The current version of the application restricts the
+addition of contacts with identical names, assuming that each contact should have a unique name. However, it is not
+uncommon for people to have the same name, and this restriction can be limiting. We propose to enhance the application
+to allow multiple contacts with the same name, while ensuring that each contact is uniquely identifiable by other means
+such as company name, email, or phone number. The updated application will allow the addition of contacts with the same
+name. To differentiate between contacts with identical names, additional details such as company name, email, or phone
+number will be used. This approach will maintain the uniqueness of each contact within the application. Adjust the
+contact validation logic to check for uniqueness based on the combination of name and one or more of the additional
+identifying details. If a contact with the same name and other identifying details already exists, the application will
+prompt the user to confirm the addition of the new contact instead of adding it immediately.
+
+6. **Allow `find` command to search contact list with partial name/company name matches**: The existing `find`
+command
+focuses on exact matches for names or company names. This limitation can be restrictive, especially when users are
+unsure about the complete name or are looking for contacts with names that have common substrings. To provide a more
+flexible and intuitive search experience, we plan to enhance the find command to support partial matching. The improved
+find command will enable users to search for contacts using partial names or partial company names. The command will
+display a list of contacts where the entered term matches any part of the person's name or company name. (e.g. `find j`
+will return contacts with names like "John" and company names like "JPMorgan".)
+
+7. **Store the resume such that the user can retrieve it later**. The existing implementation of the program
+does not store the user's resume but only binds it to the current instance of the program. This can be limiting
+as users would have to re-input their resume everytime they open the application. Even thought it is unlikely that
+a resume can change as often as a contact in the addressbook. To provide a better user experience, we plan to store the
+resume and enable the application to read the stored resume, if any, whenever it starts.
+
+8. **Allow user to edit the resume**. The existing implementation of the program, does not allow users to edit the
+resume. Currently, user would have to call `resume` command and re-input the values if they want to update them. This
+can be limiting as it results in unnecessary inconvenience of having to re-input all the values instead of editing just
+the intended one. To provide a more intuitive experience, we plan to enhance the `edit` command such that users can
+directly access the current resume and edit the values. (e.g `edit resume s/3000` will update the salary on the resume
+to 3000)
+
+9. **Allow user to store multiple versions of the resume**. The existing implementation does not allow users to store
+multiple resumes. This can be limiting as users may want to retrieve specific versions of the resume. To make the
+experience more intuitive, we plan to create a separate storage system to allow users to store multiple resumes. For
+instance, calling the `resume` command will create a separate resume to store, instead of overwriting the current
+resume.
+
+10. **Ask for confirmation from users when `delete` and `clear` command is executed**: The current implementation
+ allows users to clear and delete contacts from the contact list. Users may accidentally delete important
+ contacts or misunderstand the function of the commands. Hence, we plan to show a warning to tell them that `delete`
+ will cause the contact to be deleted permanently and that `clear` will clear the whole list permanently and
+ thereafter ask for a confirmation to exceute the commands.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 7abd1984218..2115c0481bf 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -2,24 +2,47 @@
layout: page
title: User Guide
---
+### Introduction
+Welcome to CCBot and thank you for choosing CCBot!
+>_"Connecting lives, Connecting careers" ~CCBot_
-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.
+CareerConnectBot (CCBot) is a **desktop app for managing job interview contacts, for you computing professionals!**
+**It 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, CCBot can get your contact management tasks done **faster** than traditional
+GUI apps.
+### Key features
+With CCBot, you can keep track and manage your various job applications by:
+* **Filtering and sorting your contact list flexibly**
+* **Predicting the job difficulty of each of your applied job**
+* **Adding additional notes about each of your company contact**
+* **Adding interview times, salary, required technical skills, and priority to each of your company contact**
+
+_All in one app!_
+
+For more details on what CCBot has to offer, check out the [Features](#features) section below!
+
+## About
+This user guide serves as a manual with instructions for downloading, installing, setting up and using CCBot.
+
+Sections of the guide are split into the relevant chapters listed in the [Table Of Contents](#table-of-contents).
+If you need to look for how to use a specific command, you may skip to the relevant chapter.
+
+## Table of Contents
* Table of Contents
{:toc}
--------------------------------------------------------------------------------------------------------------------
-
## Quick start
1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+1. Download the latest `CCBOT.jar` from [here](https://github.com/AY2324S2-CS2103T-T08-3/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+1. Copy the file to the folder you want to use as the _home folder_ for your CCBot.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
+1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar CCBOT.jar` command to run the application.
+ A GUI similar to the picture below should appear in a few seconds. Note how the app contains some sample data.

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.
@@ -27,11 +50,15 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
* `list` : Lists all contacts.
- * `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.
+ * `add cn/Google n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 tt/121220221400
+ i/remote work s/5000 pl/Java t/friends t/referral pri/2` :
+ Adds a contact named `John Doe` to the Address Book.
* `delete 3` : Deletes the 3rd contact shown in the current list.
- * `clear` : Deletes all contacts.
+ * `clear` : Deletes all contacts.
+ * Note that this action is irreversible so use it only after trying the above commands to clear the example
+ contacts.
* `exit` : Exits the app.
@@ -63,9 +90,54 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
* If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
+### Priority
+>From 0-4 our program has 5 priorities. The lower the value, the higher the priority.
+
+
+
+**0 - High Priority** - This is the highest priority.
+
+
+
+**1 - Medium Priority** - This is the second highest priority.
+
+
+
+**2 - Low Priority** - This is the third highest priority.
+
+
+
+**3 - Very Low Priority** - This is the fourth highest priority.
+
+
+
+**4 - Lowest Priority** - This is the lowest priority.
+
+--------------------------------------------------------------------------------------------------------------------
+### Date and Time
+> Your CCBot uses date and time to better help you manage your interviews. This section contains all the details on how
+> your CCBot interprets date and time.
+
+* ### Format : `ddMMyyyyHHmm`
+ * `dd` - refers to the day and the acceptable range is from **01** to **31**
+ * `MM` - refers to the month and the acceptable range is from **01** to **12**
+ * `yyyy` - refers to the year and accepts any **4-digit** numbers from **0001** to **9999**
+ * `HH` - refers to the hour and the acceptable range is from **00** to **23**
+ * `mm` - refers to the minutes and the acceptable range is from **00** to **59**
+* ### Examples:
+ * `121220221400` is interpreted as **December 12, 2022 4:00 PM**
+ * `010100010000` is interpreted as **January 01, 0001 12:00 AM**
+> #### Handling leap years
+> * Your CCBot uses the ISO-8601 calendar system to handle leap years. This means that giving a leap day on a non-leap
+ > year returns the last valid day of that month.
+> * Example: `290220090000` will give the same output as `280220090000`
+> * For more information, click [here](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html).
+
+--------------------------------------------------------------------------------------------------------------------
+
### Viewing help : `help`
-Shows a message explaning how to access the help page.
+Shows a message explaining how to access the help page.

@@ -76,64 +148,190 @@ Format: `help`
Adds a person to the address book.
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+Format: `add cn/COMPANY_NAME n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [tt/INTERVIEW_TIME] [i/INFO]
+ [s/SALARY] [pl/PROGRAMMING_LANGUAGE]... [t/TAG]... [pri/PRIORITY(0-4)]`
:bulb: **Tip:**
A person can have any number of tags (including 0)
+* Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs.
+
+Examples:
+* `add cn/Google n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 tt/121220221400
+i/Birthday: 12 May 2001 s/5000 pl/Java t/friends t/owesMoney pri/2`
+* `add cn/ Amazon n/Betsy Crowe p/81234567 e/betsycrowe@example.com a/Newgate Prison tt/121220241200
+i/Remote work s/4000 pl/Python t/criminal pri/4`
+
+### Adding a resume: `resume`
+
+Adds a resume.
+
+Format: `resume cn/COMPANY_NAME n/NAME p/PHONE_NUMBER a/ADDRESS e/EMAIL s/SALARY edu/EDUCATION
+[pl/PROGRAMMING_LANGUAGE]...`
+
+* Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs.
+
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`
+* `resume cn/Google n/John Doe p/98765432 e/johnd@example.com s/3000 edu/NUS a/311, Clementi Ave 2, #02-25 pl/Java pl/C++`
+* `resume cn/Apple n/Amy Birch p/87654321 e/amy@example.com s/3000 edu/NUS a/311, Clementi Ave 2, #02-25`
+
### Listing all persons : `list`
Shows a list of all persons in the address book.
+_Note: Any extra parameters after `list` will be ignored as it displays the full address book._
+
Format: `list`
+
+**:information_source: Note:** Extraneous parameters for `list` will be ignored. (e.g. `list 1` is interpreted
+`list`.) If you want to find a person in the contact list, refer to the `find` or `filter` feature.
+
### Editing a person : `edit`
Edits an existing person in the address book.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Format: `edit INDEX [cn/COMPANY_NAME] [n/NAME] [p/PHONE_NUMBER] [e/EMAIL a/ADDRESS] [tt/INTERVIEW_TIME] [i/INFO]
+[s/SALARY] [pl/PROGRAMMING_LANGUAGE]... [t/TAG]... [pri/PRIORITY(0-4)]`
-* 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, …
+* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list.
* 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.
+* When editing tags and info, the existing tags and info of the person will be removed i.e adding of tags and info are
+ not cumulative.
+ * You can remove all the person’s tags by typing `t/` without specifying any tags after it.
+ * You can remove all the person’s info by typing `i/` without specifying any info after it.
+* Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs.
+* 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.
-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`
-Finds persons whose names contain any of the given keywords.
+### Locating persons by name / company name: `find`
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Finds persons whose names / company names contain any of the given keywords.
+
+Format: `find KEYWORD [KEYWORDS]`
* 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 name and company 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`
Examples:
-* `find John` returns `john` and `John Doe`
+* `find John` returns `John` and `John Doe`
+* `find google` returns `google` and `Google`
+* `find mary tiktok` returns `Mary Lee` and `Tiktok`
* `find alex david` returns `Alex Yeoh`, `David Li`
- 
+ 
+
+### Locating persons by various categories: `filter`
+
+Filters contact list based on tags, interview times, salary range, or programming languages.
+
+#### Filter by tag: `filter t/`
+
+Format: `filter t/TAG [TAGS]...`
+
+* The search is case-sensitive.
+* Only the tags of each of the contacts are searched.
+* Persons matching at least one tag will be returned.
-### Deleting a person : `delete`
+Examples:
+* `filter t/manager` returns any persons with a tag, `manager`
+* `filter t/manager HR` returns any persons with either of the tags, `manager` or `HR`.
+
+#### Filter by interview times: `filter tt/`
+
+Format: `filter tt/INTERVIEW_TIME_RANGE [INTERVIEW_TIME_RANGE]...`
+
+* Only the interview times of each of the contacts are searched.
+* Persons with interview times within the range provided will be returned.
+* Valid `INTERVIEW_TIME_RANGE` includes:
+ * `before/INTERVIEW_TIME`
+ * `after/INTERVIEW_TIME`
+ * `from/INTERVIEW_TIME-INTERVIEW_TIME`
+ * Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs for
+ `INTERVIEW_TIME`.
+
+Examples:
+* `filter tt/before/010120200000 from/010120220000-010120230000` returns persons with interview times before 1 Jan
+ 2020, 1200am `(010120200000)` or persons with interview times within 1 Jan 2022, 1200am `(010120220000)` and 1 Jan
+ 2023, 1200am `(010120230000)`.
+* `filter tt/after/010120220000` returns persons with interview times after 1 Jan 2022, 1200am `(010120220000)`.
+
+#### Filter by salaries: `filter s/`
+
+Format: `filter s/SALARY_RANGE [SALARY_RANGE]...`
+
+* Only the salaries of each of the contacts are searched.
+* Persons with salaries within the range provided will be returned.
+* Valid `SALARY_RANGE` includes:
+ * [Acceptable values for `SALARY`](#parameter-constraints)
+ * `>=INTEGER`
+ * `<=INTEGER`
+
+ where `INTEGER` is a number inclusive of and between 0 and 2147483647.
+
+Examples:
+* `filter s/5000` returns persons with salaries of $5000.
+* `filter s/2000-5000 >=7000` returns persons with salaries that contain any number from $2000 to $5000 or with
+ salaries more than or equals to $7000. (e.g. persons with salaries `3000-6000`, `4000`, `8000-20900` are returned).
+
+#### Filter by programming language: `filter pl/`
+
+Format `filter pl/PROGRAMMING_LANGUAGE [PROGRAMMING_LANGUAGE]...`
+
+* The search is case-insensitive.
+* Only the programming language of each of the contacts are searched.
+* Persons matching at least one programming language will be returned.
+* Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs for `PROGRAMMING_LANGUAGE`.
+
+Examples:
+* `filter pl/Java` returns any persons with a programming language, `java`.
+* `filter pl/python C` returns any persons with either of the programming languages, `python` or `c`.
+
+### Sorting the person list : `sort`
+
+Sorts the person list by the specified field.
+
+Format: `sort [rev/] KEYWORD`
+
+* Sorts the person list by the specified `KEYWORD`.
+* The `KEYWORD` must be one of the following: `n/` (name), `cn/` (company name),`tt/` (interview time), `s/` (salary), `pri/` (priority).
+* The `rev/` prefix can be added to sort in reverse order. (Optional)
+* The sorting is not case-insensitive.
+* The sort command defaults to alphabetical sorting for names and company names.
+* The sort command defaults to chronological sorting for interview times.
+* The sort command defaults to sort from largest to smallest for salary.
+* The sort command defaults to sort from the highest priority to the lowest priority for priority.
+
+Examples:
+* `sort n/` sorts the person list by name in alphabetical order.
+* `sort rev/ s/` sorts the person list by salary in descending order.
+* `sort tt/` sorts the person list by interview time in chronological order.
+* `sort rev/ pri/` sorts the person list by priority in descending order.
+* `sort cn/` sorts the person list by company name in alphabetical order.
+* `sort rev/ cn/` sorts the person list by company name in reverse alphabetical order.
+* `sort rev/ tt/` sorts the person list by interview time in reverse chronological order.
+
+### Deleting a person/persons: `delete`
+
+Deletes the contact list based index or tags.
+
+#### Delete by index: `delete`
Deletes the specified person from the address book.
Format: `delete INDEX`
* Deletes the person at the specified `INDEX`.
+ * Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs for `INDEX`.
* The index refers to the index number shown in the displayed person list.
* The index **must be a positive integer** 1, 2, 3, …
@@ -141,13 +339,30 @@ 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.
+#### Delete by tag: `delete t/`
+
+Format: `delete t/TAG [TAG]...`
+
+* The search is case-insensitive.
+* Only contacts that have the tag are deleted.
+* Persons matching the tag will be deleted.
+* Refer to [parameter constraints table](#parameter-constraints) for more details on acceptable inputs for `TAG`.
+
+Examples:
+* `delete t/manager` deletes any persons with a tag, `manager`
+
### Clearing all entries : `clear`
-Clears all entries from the address book.
+Clears **all** entries from the address book.
Format: `clear`
-### Exiting the program : `exit`
+
:exclamation: **Caution:**
+Extraneous parameters for `clear` will be ignored. (e.g. `clear 1` is interpreted as `clear`)
+If you only want to clear **some** and **not all** entries from the address book, refer to `delete` feature.
+
+
+### Exiting the program : `exit`
Exits the program.
@@ -155,27 +370,38 @@ Format: `exit`
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+CCBot data are saved in the hard disk automatically after any command that changes the data. There is no need to save
+manually.
+
+
:exclamation: **Caution:**
+Resumes added will not be saved in the hard disk as of v1.4.
+
+
### Editing the data file
-AddressBook data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+CCBot data are saved automatically as a JSON file `[JAR file location]/data/addressbook.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. Hence, it is recommended to take a backup of the file before editing it.
-Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
+If your changes to the data file makes its format invalid, CCBot will discard all data and start with an empty data
+file at the next run. Hence, it is recommended to take a backup of the file before editing it.
+Furthermore, certain edits can cause the CCBot to behave in unexpected ways (e.g., if a value entered is outside of the
+acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
-### Archiving data files `[coming in v2.0]`
+### Job difficulty
+The job difficulty is automatically generated by our self-developed algorithm with an evaluation factor ranging from 0% to 100%. A higher value means that the algorithm guesses the difficulty or competition of getting the job.
-_Details coming soon ..._
+This value cannot be modified or added by the `edit` or `add` commands.
--------------------------------------------------------------------------------------------------------------------
## 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 CCBot home folder.
--------------------------------------------------------------------------------------------------------------------
@@ -187,12 +413,51 @@ _Details coming soon ..._
## Command summary
-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`
+| Action | Format, Examples |
+|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add** | `add cn/COMPANY_NAME n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [tt/INTERVIEW_TIME] [i/INFO] [s/SALARY] [pl/PROGRAMMING_LANGUAGE]... [t/TAG]... [pri/PRIORITY(0-4)]` 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` `delete t/TAG [TAG]...` e.g., `delete t/HR Manager` |
+| **Edit** | `edit INDEX [cn/COMPANY_NAME] [n/NAME] [p/PHONE_NUMBER] [e/EMAIL a/ADDRESS] [tt/INTERVIEW_TIME]
[i/INFO] [s/SALARY] [pl/PROGRAMMING_LANGUAGE]... [t/TAG]... [pri/PRIORITY(0-4)]` e.g.,`edit 2 n/James Lee e/jameslee@example.com` |
+| **Find** | `find KEYWORD [KEYWORD]...` e.g., `find James Jake` |
+| **Filter** | `filter t/TAG [TAG]...` e.g., `filter t/manager HR` `filter tt/INTERVIEW_TIME_RANGE [INTERVIEW_TIME_RANGE]...` e.g., `filter tt/before/010120200000 from/010120220000-010120230000 after/010120220000` `filter s/SALARY_RANGE [SALARY_RANGE]...` e.g., `filter s/2000-5000 >=7000` `filter pl/PROGRAMMING_LANGUAGE [PROGRAMMING_LANGUAGE]...` e.g., `filter pl/python C` |
+| **List** | `list` |
+| **Help** | `help` |
+| **Sort** | `sort` or `sort rev/ [pri/PRIORITY] [n/NAME] [cn/COMPANY_NAME] [s/SALARY] [tt/INTERVIEW_TIME] [jd/JOB_DIFFICULTY]` e.g., `sort pri/` e.g., `sort rev/ tt/` |
+| **Resume** | `resume cn/COMPANY_NAME n/NAME p/PHONE e/EMAIL edu/EDUCATION s/SALARY [pl/PROGRAMMING_LANGUAGE]...` e.g., `resume cn/Google n/John Doe p/98765432 e/johnd@example.com s/3000 edu/NUS a/311, Clementi Ave 2, #02-25 pl/Java pl/C++ ` |
+
+## CLI Syntax Summary
+
+| Character | Explaination, Examples |
+|-----------|----------------------------------------------|
+| **n/** | Name of the contact |
+| **cn/** | The company name |
+| **tt/** | The time of the interview |
+| **s/** | The salary |
+| **a/** | The place of residence |
+| **e/** | The email address |
+| **i/** | Any additional info |
+| **pri/** | Priority of the job |
+| **edu/** | Education level |
+| **pl/** | Programming languages |
+| **jd/** | The job difficulty (only for `sort` command) |
+
+## Parameter Constraints
+
+| Field | Constraint |
+|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `COMPANY_NAME` | Should be less than 100 characters, and it should not be blank. |
+| `NAME` | Should only contain alphanumeric characters and spaces, and it should not be blank. |
+| `PHONE_NUMBER` | Should only contain numbers, and it should be at least 3 digits long. |
+| `EMAIL` | Should be a valid email address. |
+| `ADDRESS` | Can take any values, and it should not be blank. |
+| `SALARY` | Should only contain numbers, with range [0, 2147483647] or two pure digital numbers with '-' in between. Both digital numbers should be within the range [0, 2147483647]. |
+| `PROGRAMMING_LANGUAGE` | Should be alphanumeric and may contain some special characters (+ and #), and must be less than 50 characters. |
+| `TAG` | Should be a single alphanumerical word that does not contain spaces.
|
+| `PRIORITY` | Should be a number between 0 and 4. |
+| `INTERVIEW_TIME` | Should be in the format `ddMMyyyyHHmm`. * `dd` - refers to the day and the acceptable range is from **01** to **31** * `MM` - refers to the month and the acceptable range is from **01** to **12** * `yyyy` - refers to the year and accepts any **4-digit** numbers from **0001** to **9999** * `HH` - refers to the hour and the acceptable range is from **00** to **23** * `mm` - refers to the minutes and the acceptable range is from **00** to **59** |
+| `INFO` | Can take any values, and it should not be blank. |
+| `EDUCATION` | Should only contain alphanumeric characters and spaces, and it should not be blank. |
+| `INDEX` | The index **must be a positive integer** 1, 2, 3, … _Note: CCBot does not consider 0 to be a positive integer_ |
+
+_Navigate back to [Table Of Contents](#table-of-contents)_
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..c783e49fc00 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "CCBot"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "nus-cs2103-AY2324S2/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..f3a62867bdc 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: "CCBot";
font-size: 32px;
}
}
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..da4c9aeb347 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -13,9 +13,14 @@ UniqueTagList -right-> "*" Tag
UniquePersonList -right-> Person
Person -up-> "*" Tag
+Person -up-> "*" ProgammingLanguage
Person *--> Name
Person *--> Phone
Person *--> Email
Person *--> Address
+Person *--> CompanyName
+Person *--> InterviewTime
+Person *-right-> Salary
+Person *-right-> Info
@enduml
diff --git a/docs/diagrams/DeleteTagSequenceDiagram.puml b/docs/diagrams/DeleteTagSequenceDiagram.puml
new file mode 100644
index 00000000000..bd5fa31d3ff
--- /dev/null
+++ b/docs/diagrams/DeleteTagSequenceDiagram.puml
@@ -0,0 +1,70 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":DeleteTagCommandParser" as DeleteTagCommandParser LOGIC_COLOR
+participant "d:DeleteTagCommand" as DeleteTagCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("delete t/friend")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("delete t/friend")
+activate AddressBookParser
+
+create DeleteTagCommandParser
+AddressBookParser -> DeleteTagCommandParser
+activate DeleteTagCommandParser
+
+DeleteTagCommandParser --> AddressBookParser
+deactivate DeleteTagCommandParser
+
+AddressBookParser -> DeleteTagCommandParser : parse("friend")
+activate DeleteTagCommandParser
+
+create DeleteTagCommand
+DeleteTagCommandParser -> DeleteTagCommand
+activate DeleteTagCommand
+
+DeleteTagCommand --> DeleteTagCommandParser :
+deactivate DeleteTagCommand
+
+DeleteTagCommandParser --> AddressBookParser : d
+deactivate DeleteTagCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteTagCommandParser -[hidden]-> AddressBookParser
+destroy DeleteTagCommandParser
+
+AddressBookParser --> LogicManager : d
+deactivate AddressBookParser
+
+LogicManager -> DeleteTagCommand : execute(m)
+activate DeleteTagCommand
+
+DeleteTagCommand -> Model : deletePerson(tag)
+activate Model
+
+Model --> DeleteTagCommand
+deactivate Model
+
+create CommandResult
+DeleteTagCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteTagCommand
+deactivate CommandResult
+
+DeleteTagCommand --> LogicManager : r
+deactivate DeleteTagCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/JobDifficultyDiagram.puml b/docs/diagrams/JobDifficultyDiagram.puml
new file mode 100644
index 00000000000..c4925d751ad
--- /dev/null
+++ b/docs/diagrams/JobDifficultyDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+class JobDifficulty {
+ -difficulty : int
+ --
+ +JobDifficulty(CompanyName, Salary) : void
+ +getDifficulty() : int
+ +toString() : String
+}
+class CompanyName {
+ -companyName : String
+}
+class Salary {
+ -salary : int
+}
+JobDifficulty *-- CompanyName
+JobDifficulty *-- Salary
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index 58b4f602ce6..c66093078dc 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -11,7 +11,15 @@ package "Parser Classes" as ParserClasses{
Class XYZCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
-
+Class AddCommand
+Class ClearCommand
+Class DeleteCommand
+Class EditCommand
+Class ExitCommand
+Class FindCommand
+Class HelpCommand
+Class ListCommand
+Class SortCommand
Class "<>\nLogic" as Logic
Class LogicManager
@@ -31,7 +39,15 @@ LogicManager .right.|> Logic
LogicManager -right->"1" ParserClasses
ParserClasses ..> XYZCommand : <>
-XYZCommand -up-|> Command
+AddCommand -up-|> Command
+ClearCommand -up-|> Command
+DeleteCommand -up-|> Command
+EditCommand -up-|> Command
+ExitCommand -up-|> Command
+FindCommand -up-|> Command
+HelpCommand -up-|> Command
+ListCommand -up-|> Command
+SortCommand -up-|> Command
LogicManager .left.> Command : <>
LogicManager --> Model
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..e9d3dafc3e3 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -15,10 +15,17 @@ Class UserPrefs
Class UniquePersonList
Class Person
Class Address
+Class CompanyName
Class Email
+Class Info
+Class InterviewTime
Class Name
Class Phone
+Class Salary
Class Tag
+Class ProgammingLanguage
+Class JobDifficulty
+Class Priority
Class I #FFFFFF
}
@@ -37,11 +44,18 @@ UserPrefs .up.|> ReadOnlyUserPrefs
AddressBook *--> "1" UniquePersonList
UniquePersonList --> "~* all" Person
-Person *--> Name
+Person *-left-> Name
Person *--> Phone
Person *--> Email
Person *--> Address
+Person *--> Info
+Person *--> CompanyName
+Person *--> Salary
+Person *--> InterviewTime
+Person *--> JobDifficulty
+Person *--> Priority
Person *--> "*" Tag
+Person *-right-> "*" ProgammingLanguage
Person -[hidden]up--> I
UniquePersonList -[hidden]right-> I
diff --git a/docs/diagrams/SortComparatorClass.puml b/docs/diagrams/SortComparatorClass.puml
new file mode 100644
index 00000000000..2785292376c
--- /dev/null
+++ b/docs/diagrams/SortComparatorClass.puml
@@ -0,0 +1,14 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+
+Comparator <|-- PersonCompanyNameComparator
+Comparator <|-- NameContainsKeywordsPredicate
+Comparator <|-- PersonInterviewTimeComparator
+Comparator <|-up- PersonNameComparator
+Comparator <|-up- PersonPriorityComparator
+Comparator <|-up- PersonSalaryComparator
+
+@enduml
diff --git a/docs/diagrams/SortSequenceDiagram.puml b/docs/diagrams/SortSequenceDiagram.puml
new file mode 100644
index 00000000000..4dbf150b6f0
--- /dev/null
+++ b/docs/diagrams/SortSequenceDiagram.puml
@@ -0,0 +1,46 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+Actor User as user USER_COLOR
+Participant ":UI" as ui UI_COLOR
+Participant ":Logic" as logic LOGIC_COLOR
+Participant ":Model" as model MODEL_COLOR
+Participant "AddressBook" as addressBook MODEL_COLOR
+Participant ":Storage" as storage STORAGE_COLOR
+
+user -[USER_COLOR]> ui : "sort pri/"
+activate ui UI_COLOR
+
+ui -[UI_COLOR]> logic : execute("sort pri/")
+activate logic LOGIC_COLOR
+
+logic -[LOGIC_COLOR]> model : updateSortedPersonList(p)
+activate model MODEL_COLOR
+
+model -[MODEL_COLOR]> addressBook : sortPersons(info)
+activate addressBook MODEL_COLOR
+
+addressBook -[MODEL_COLOR]> model
+deactivate addressBook
+
+model -[MODEL_COLOR]-> logic
+deactivate model
+
+logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+activate storage STORAGE_COLOR
+
+storage -[STORAGE_COLOR]> storage : Save to file
+activate storage STORAGE_COLOR_T1
+storage --[STORAGE_COLOR]> storage
+deactivate storage
+
+storage --[STORAGE_COLOR]> logic
+deactivate storage
+
+logic --[LOGIC_COLOR]> ui
+deactivate logic
+
+ui--[UI_COLOR]> user
+deactivate ui
+@enduml
diff --git a/docs/diagrams/SortSqDiagram.puml b/docs/diagrams/SortSqDiagram.puml
new file mode 100644
index 00000000000..bf9e13a1389
--- /dev/null
+++ b/docs/diagrams/SortSqDiagram.puml
@@ -0,0 +1,77 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":SortCommandParser" as SortCommandParser LOGIC_COLOR
+participant "s:SortCommand" as SortCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+Participant "AddressBook" as addressBook MODEL_COLOR
+end box
+
+[-> LogicManager : execute("sort pri/")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("sort pri/")
+activate AddressBookParser
+
+create SortCommandParser
+AddressBookParser -> SortCommandParser
+activate SortCommandParser
+
+SortCommandParser --> AddressBookParser
+deactivate SortCommandParser
+
+AddressBookParser -> SortCommandParser : parse("pri/")
+activate SortCommandParser
+
+create SortCommand
+SortCommandParser -> SortCommand
+activate SortCommand
+
+SortCommand --> SortCommandParser :
+deactivate SortCommand
+
+SortCommandParser --> AddressBookParser : s
+deactivate SortCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+SortCommandParser -[hidden]-> AddressBookParser
+destroy SortCommandParser
+
+AddressBookParser --> LogicManager : s
+deactivate AddressBookParser
+
+LogicManager -> SortCommand : execute(m)
+activate SortCommand
+
+SortCommand -> Model : updateSortedPersonList(p)
+activate Model
+
+Model -> addressBook : sortPersons(info)
+activate addressBook
+
+addressBook --> Model
+deactivate addressBook
+
+Model --> SortCommand
+deactivate Model
+
+create CommandResult
+SortCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> SortCommand
+deactivate CommandResult
+
+SortCommand --> LogicManager : r
+deactivate SortCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..e1ecb2d0853 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -15,6 +15,7 @@ Class PersonListPanel
Class PersonCard
Class StatusBarFooter
Class CommandBox
+Class ResumeWindow
}
package Model <> {
@@ -34,6 +35,7 @@ MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
MainWindow *-down-> "1" PersonListPanel
MainWindow *-down-> "1" StatusBarFooter
+MainWindow *-down-> "0..1" ResumeWindow
MainWindow --> "0..1" HelpWindow
PersonListPanel -down-> "*" PersonCard
@@ -46,6 +48,7 @@ PersonListPanel --|> UiPart
PersonCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
+ResumeWindow -left-|> UiPart
PersonCard ..> Model
UiManager -right-> Logic
diff --git a/docs/diagrams/UserDiagram.puml b/docs/diagrams/UserDiagram.puml
new file mode 100644
index 00000000000..bcb91f9c6b8
--- /dev/null
+++ b/docs/diagrams/UserDiagram.puml
@@ -0,0 +1,43 @@
+@startuml
+'https://plantuml.com/class-diagram
+
+class User
+
+class Salary {
+ -salary : int
+}
+
+class CompanyName {
+ -companyName : String
+}
+
+class Name {
+ -name : String
+}
+
+class Address {
+ -address : String
+}
+
+class Education {
+ -education : String
+}
+
+class Email {
+ -email : String
+}
+class Phone {
+ -phone : String
+}
+class ProgrammingLanguage {
+}
+
+User *-- "1" CompanyName
+User *-- "1" Salary
+User *-- "1" Name
+User *-- "1" Address
+User *-- "1" Education
+User *-- "1" Email
+User *-- "1" Phone
+User *-- "0..1" ProgrammingLanguage
+@enduml
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 02a42e35e76..8cd4e02eb0a 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/DeleteTagSeqDiagram.png b/docs/images/DeleteTagSeqDiagram.png
new file mode 100644
index 00000000000..37bd9bfc0eb
Binary files /dev/null and b/docs/images/DeleteTagSeqDiagram.png differ
diff --git a/docs/images/FindExample.png b/docs/images/FindExample.png
new file mode 100644
index 00000000000..c18308c2033
Binary files /dev/null and b/docs/images/FindExample.png differ
diff --git a/docs/images/JobDifficultyDiagram.png b/docs/images/JobDifficultyDiagram.png
new file mode 100644
index 00000000000..d3bb4d53d71
Binary files /dev/null and b/docs/images/JobDifficultyDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index a19fb1b4ac8..84d98f6e994 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/SortSequenceDiagram.png b/docs/images/SortSequenceDiagram.png
new file mode 100644
index 00000000000..3e8e9469ec4
Binary files /dev/null and b/docs/images/SortSequenceDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..c4b20df3273 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram2.png b/docs/images/UiClassDiagram2.png
new file mode 100644
index 00000000000..2f9219439fb
Binary files /dev/null and b/docs/images/UiClassDiagram2.png differ
diff --git a/docs/images/UserDiagram.png b/docs/images/UserDiagram.png
new file mode 100644
index 00000000000..284ab836f9d
Binary files /dev/null and b/docs/images/UserDiagram.png differ
diff --git a/docs/images/ashley1.png b/docs/images/ashley1.png
new file mode 100644
index 00000000000..0fb6200ff26
Binary files /dev/null and b/docs/images/ashley1.png differ
diff --git a/docs/images/johndoe.png b/docs/images/ashleyy2444.png
similarity index 100%
rename from docs/images/johndoe.png
rename to docs/images/ashleyy2444.png
diff --git a/docs/images/dabzpengu.png b/docs/images/dabzpengu.png
new file mode 100644
index 00000000000..ed923a840c0
Binary files /dev/null and b/docs/images/dabzpengu.png differ
diff --git a/docs/images/dexter-wong.png b/docs/images/dexter-wong.png
new file mode 100644
index 00000000000..0f926e7caa2
Binary files /dev/null and b/docs/images/dexter-wong.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..0388cd13802 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/lalelulilulela.png b/docs/images/lalelulilulela.png
new file mode 100644
index 00000000000..1ce7ce16dc8
Binary files /dev/null and b/docs/images/lalelulilulela.png differ
diff --git a/docs/images/sortoverview2.png b/docs/images/sortoverview2.png
new file mode 100644
index 00000000000..780d67e5cb3
Binary files /dev/null and b/docs/images/sortoverview2.png differ
diff --git a/docs/images/zhangtianyao1.png b/docs/images/zhangtianyao1.png
new file mode 100644
index 00000000000..69c5fd87b0f
Binary files /dev/null and b/docs/images/zhangtianyao1.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..b6ffd2b8a61 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,18 @@
---
layout: page
-title: AddressBook Level-3
+title: CCBOT
---
[](https://github.com/se-edu/addressbook-level3/actions)
-[](https://codecov.io/gh/se-edu/addressbook-level3)
+[](https://codecov.io/gh/AY2324S2-CS2103T-T08-3/tp)
+

-**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).
+**CCBOT is a desktop application for managing your job application details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-* 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.
+* If you are interested in using CCBOT, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing CCBOT, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/docs/team/ashley.md b/docs/team/ashley.md
new file mode 100644
index 00000000000..3b2c22395d4
--- /dev/null
+++ b/docs/team/ashley.md
@@ -0,0 +1,54 @@
+---
+layout: page
+title: Ashley’s Project Portfolio Page
+---
+
+### Project: CCBOT
+
+CCBOT is a desktop application for managing your job application details. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added an additional component, programming language, which is saved in the addressbook.
+ * What it does: Allow users to input programming languages that are being used in the job that they applied for.
+ * Justification: This feature improves the product significantly because a user can recognise which specific technical skill is required for that particular role.
+ * 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.
+
+
+* **New Feature**: Allows users to filter by company name.
+ * What it does: Allows users to find a contact based on the company name.
+ * Justification: This feature improves the product significantly because users can easily find the person based on the company that they applied for.
+ * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation was not too challenging. It required changes to existing commands.
+
+
+* **New Feature**: Added the ability to filter by programming language.
+ * What it does: Allow users to filter contacts based on programming language.
+ * Justification: This feature improves the product significantly because a user can easily find contacts of the jobs that they applied for in which require the specific programming language.
+ * 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.
+
+
+* **New Feature**: Added the ability to delete by tag command.
+ * What it does: Allows users to delete contacts based on the tags given to each contact.
+ * Justification: This feature improves the product significantly because users can easily delete the contacts of everyone who has the same tag.
+ * 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.
+
+
+* **Project management**:
+ * Managed releases v1.2 - v1.4 (4 releases) on GitHub
+
+
+* **Enhancements to existing features**:
+ * Add find by company name in addition to find by name (Pull Request [\#70]())
+ * Add programming language to person card (Pull Request [\#34]())
+
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features find (filter by name and company name), filter programming language and delete by tag (Pull Request [\#89]())
+ * Developer Guide:
+ * Added implementation details for delete by tag feature. (Pull Request [\#191]())
+ * Added implementation details for find feature. (Pull Request [\#191]())
+ * Added planned enhancement 6. (Pull Request [\#196]())
+ * Added planned enhancement 7. (Pull Request [\#193]())
+ * Update UML diagram. (Pull Request [\#56]())
+ * Add Sequence diagram for delete tag command. (Pull Request [\#181]())
diff --git a/docs/team/dexter.md b/docs/team/dexter.md
new file mode 100644
index 00000000000..773a07794e2
--- /dev/null
+++ b/docs/team/dexter.md
@@ -0,0 +1,46 @@
+---
+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/lalelulilulela.md b/docs/team/lalelulilulela.md
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/team/zhangtianyao1.md b/docs/team/zhangtianyao1.md
new file mode 100644
index 00000000000..1b7400ac188
--- /dev/null
+++ b/docs/team/zhangtianyao1.md
@@ -0,0 +1,40 @@
+---
+layout: page
+title: Zhang Tianyao's Project Portfolio Page
+---
+
+### Project: CCBOT
+
+CCBOT is a desktop application for managing your job application details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to sort person list.
+ * What it does: allows the user to sort the person list by name, company name, job difficulty, priority, salary, and interview date.
+ * Justification: This feature improves the product significantly because a user can easily find the person he/she wants to check.
+ * 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.
+
+* **New Feature**: Added the job difficulty model.
+ * What it does: allows the program auto calculate the job difficulty based on the job description.
+ * Justification: This feature improves the product significantly because a user can easily identify the job difficulty.
+ * 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.
+
+* **Project management**:
+ * Managed releases `v1.2` - `v1.4` (4 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Add salary range to the person card (Pull requests [\#20]())
+ * Fix add command examples (Pull requests [\#35]())
+ * Add job difficulty comparator (Pull requests [\#69]())
+ * Add priority to person card (Pull requests [\#39]())
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `sort` and `job difficulty` [\#93]() [\#86]()
+ * Added documentation for the constraints of the `add`, `edit` and `add resume` command [\#169]()
+ * Developer Guide:
+ * Added implementation details of the `sort` feature.
+ * Added implementation details of the `job difficulty` feature.[\#54]()
+ * Update UML diagrams. [\#37]()
+ * Add UML diagrams for `sort` command. [\#43]()
+
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java
index 8cf8e15a0f0..fc3965de91b 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/address/commons/core/LogsCenter.java
@@ -20,7 +20,7 @@
public class LogsCenter {
private static final int MAX_FILE_COUNT = 5;
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
- private static final String LOG_FILE = "addressbook.log";
+ private static final String LOG_FILE = "ccbot.log";
private static final Logger logger; // logger for this class
private static Logger baseLogger; // to be used as the parent of all other loggers created by this class.
private static Level currentLogLevel = Level.INFO;
@@ -79,7 +79,7 @@ private static void removeHandlers(Logger logger) {
* Sets it as the {@code baseLogger}, to be used as the parent logger of all other loggers.
*/
private static void setBaseLogger() {
- baseLogger = Logger.getLogger("ab3");
+ baseLogger = Logger.getLogger("ccbot");
baseLogger.setUseParentHandlers(false);
removeHandlers(baseLogger);
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..5813201b42c 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -18,6 +18,7 @@ public class Messages {
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
+ public static final String MESSAGE_INVALID_SORT_COMMAND_INDEX = "Invalid sort command index";
/**
* Returns an error message indicating the duplicate prefixes.
@@ -36,15 +37,29 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
*/
public static String format(Person person) {
final StringBuilder builder = new StringBuilder();
- builder.append(person.getName())
+ builder.append("Company name: ")
+ .append(person.getCompanyName())
+ .append("; Name: ")
+ .append(person.getName())
.append("; Phone: ")
.append(person.getPhone())
.append("; Email: ")
.append(person.getEmail())
.append("; Address: ")
.append(person.getAddress())
+ .append("; Interview Date and Time: ")
+ .append(person.getDateTime())
+ .append("; Salary: ")
+ .append(person.getSalary())
+ .append("$")
+ .append("; Info: ")
+ .append(person.getInfo())
.append("; Tags: ");
person.getTags().forEach(builder::append);
+ builder.append("; Programming Languages: ");
+ person.getProgrammingLanguages().forEach(builder::append);
+ builder.append("; Priority: ")
+ .append(person.getPriority());
return builder.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..6904b43707d 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,9 +2,15 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import seedu.address.commons.util.ToStringBuilder;
@@ -21,23 +27,34 @@ public class AddCommand extends Command {
public static final String COMMAND_WORD = "add";
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
+ + "Parameters: \n"
+ + PREFIX_COMPANY_NAME + "COMPANY NAME \n"
+ + PREFIX_NAME + "NAME \n"
+ + PREFIX_PHONE + "PHONE \n"
+ + PREFIX_EMAIL + "EMAIL \n"
+ + PREFIX_ADDRESS + "ADDRESS \n"
+ + PREFIX_INTERVIEWTIME + "INTERVIEW-TIME \n"
+ + PREFIX_INFO + "INFO \n"
+ + "[" + PREFIX_SALARY + "SALARY] \n"
+ + "[" + PREFIX_PROGRAMMING_LANGUAGE + "PROGRAMMING-LANGUAGE]...\n"
+ "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_PRIORITY + "PRIORITY(0-4)]\n"
+ "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "Google "
+ PREFIX_NAME + "John Doe "
+ PREFIX_PHONE + "98765432 "
+ PREFIX_EMAIL + "johnd@example.com "
+ PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
+ + PREFIX_INTERVIEWTIME + "121220221400 "
+ + PREFIX_INFO + "Birthday: 12 May 2001 "
+ + PREFIX_SALARY + "5000 "
+ + PREFIX_PROGRAMMING_LANGUAGE + "Java "
+ PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
+ + PREFIX_TAG + "owesMoney "
+ + PREFIX_PRIORITY + "2";
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";
-
private final Person toAdd;
/**
diff --git a/src/main/java/seedu/address/logic/commands/AddResumeCommand.java b/src/main/java/seedu/address/logic/commands/AddResumeCommand.java
new file mode 100644
index 00000000000..44643d92f6d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddResumeCommand.java
@@ -0,0 +1,58 @@
+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_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EDUCATION;
+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_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.user.User;
+
+/**
+ * Allows user to add their resume
+ */
+public class AddResumeCommand extends Command {
+
+ public static final String COMMAND_WORD = "resume";
+ public static final String MESSAGE_SUCCESS = "Resume added";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds your resume to the address book. "
+ + "Parameters: \n"
+ + PREFIX_COMPANY_NAME + "COMPANY NAME \n"
+ + PREFIX_NAME + "NAME \n"
+ + PREFIX_PHONE + "PHONE \n"
+ + PREFIX_EMAIL + "EMAIL \n"
+ + PREFIX_ADDRESS + "ADDRESS \n"
+ + PREFIX_SALARY + "SALARY \n"
+ + "[" + PREFIX_PROGRAMMING_LANGUAGE + "PROGRAMMING-LANGUAGE]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "Google "
+ + PREFIX_NAME + "John Doe "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_EMAIL + "johnd@example.com "
+ + PREFIX_SALARY + "3000 "
+ + PREFIX_EDUCATION + "NUS "
+ + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
+ + PREFIX_PROGRAMMING_LANGUAGE + "Java "
+ + PREFIX_PROGRAMMING_LANGUAGE + "C++ ";
+ private final User user;
+
+ /**
+ * Creates an AddCommand to add the specified {@code User}
+ */
+ public AddResumeCommand(User user) {
+ requireNonNull(user);
+ this.user = user;
+ }
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ return new CommandResult(MESSAGE_SUCCESS, false, true, false);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 249b6072d0d..80d2b78d6c8 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -16,15 +16,18 @@ public class CommandResult {
/** Help information should be shown to the user. */
private final boolean showHelp;
+ private final boolean showResume;
+
/** The application should exit. */
private final boolean exit;
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean showResume, boolean exit) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
+ this.showResume = showResume;
this.exit = exit;
}
@@ -33,7 +36,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);
}
public String getFeedbackToUser() {
@@ -44,6 +47,10 @@ public boolean isShowHelp() {
return showHelp;
}
+ public boolean isShowResume() {
+ return showResume;
+ }
+
public boolean isExit() {
return exit;
}
@@ -62,12 +69,13 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
+ && showResume == otherCommandResult.showResume
&& exit == otherCommandResult.exit;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, showResume, exit);
}
@Override
@@ -75,6 +83,7 @@ public String toString() {
return new ToStringBuilder(this)
.add("feedbackToUser", feedbackToUser)
.add("showHelp", showHelp)
+ .add("showResume", showResume)
.add("exit", exit)
.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteAbstractCommand.java b/src/main/java/seedu/address/logic/commands/DeleteAbstractCommand.java
new file mode 100644
index 00000000000..d28a7ca0afc
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteAbstractCommand.java
@@ -0,0 +1,22 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+/**
+ * Abstract class representing a DeleteCommand for deleting contacts or tags in an address book.
+ * Subclasses will implement specific delete commands for different types of deletions.
+ */
+public abstract class DeleteAbstractCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes the contact identified by the index number "
+ + "used in the displayed contact list or deletes contacts with the specified tag.\n"
+ + "Parameters:\n"
+ + "- " + COMMAND_WORD + " INDEX (must be a positive integer)\n"
+ + "- " + COMMAND_WORD + " " + PREFIX_TAG + "TAG\n"
+ + "Example: " + COMMAND_WORD + " 1\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_TAG + "friend";
+
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..c265694a490 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -14,7 +14,7 @@
/**
* Deletes a person identified using it's displayed index from the address book.
*/
-public class DeleteCommand extends Command {
+public class DeleteCommand extends DeleteAbstractCommand {
public static final String COMMAND_WORD = "delete";
diff --git a/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java
new file mode 100644
index 00000000000..b68f9f85420
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java
@@ -0,0 +1,82 @@
+package seedu.address.logic.commands;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+/**
+ * Command to delete all contacts with a specified tag from the address book.
+ */
+public class DeleteTagCommand extends DeleteAbstractCommand {
+ public static final String COMMAND_WORD = "delete t/";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes all contacts with the specified tag.\n"
+ + "Parameters: TAG\n"
+ + "Example: " + COMMAND_WORD + " friend";
+
+ public static final String MESSAGE_DELETE_TAG_SUCCESS = "Deleted all contacts with tag: %1$s";
+ public static final String MESSAGE_TAG_DOES_NOT_EXIST = "The following tags do not exist: %1$s";
+
+ private final TagContainsKeywordsPredicate tagToDelete;
+
+ /**
+ * Constructs a {@code DeleteTagCommand} with the specified tag to delete.
+ *
+ * @param tagToDelete The tag to delete.
+ */
+ public DeleteTagCommand(TagContainsKeywordsPredicate tagToDelete) {
+ this.tagToDelete = tagToDelete;
+ }
+
+ /**
+ * Executes the command to delete all contacts with the specified tag from the address book.
+ *
+ * @param model The address book model.
+ * @return The result of the command execution.
+ * @throws CommandException If an error occurs during command execution.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ List tags = tagToDelete.getTags();
+ List allTags = model.getAddressBook().getPersonList().stream()
+ .flatMap(person -> person.getTags().stream())
+ .distinct()
+ .collect(Collectors.toList());
+
+ if (!allTags.containsAll(tags)) {
+ List nonExistentTags = tags.stream()
+ .filter(tag -> !allTags.contains(tag))
+ .collect(Collectors.toList());
+ throw new CommandException(String.format(MESSAGE_TAG_DOES_NOT_EXIST, nonExistentTags));
+ }
+
+ List personsToDelete = model.getFilteredPersonList().stream()
+ .filter(person -> tagToDelete.test(person))
+ .collect(Collectors.toList());
+
+ personsToDelete.forEach(model::deletePerson);
+
+ return new CommandResult(String.format(MESSAGE_DELETE_TAG_SUCCESS, tagToDelete));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DeleteTagCommand)) {
+ return false;
+ }
+
+ DeleteTagCommand otherDeleteTagCommand = (DeleteTagCommand) other;
+ return tagToDelete.equals(otherDeleteTagCommand.tagToDelete);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..d98022abbf9 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,9 +2,15 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
@@ -21,11 +27,16 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
/**
@@ -39,11 +50,17 @@ public class EditCommand extends Command {
+ "by the index number used in the displayed person list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY NAME] "
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
+ + "[" + PREFIX_INTERVIEWTIME + "INTERVIEW-TIME] "
+ + "[" + PREFIX_SALARY + "SALARY] "
+ + "[" + PREFIX_INFO + "INFO] "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_PROGRAMMING_LANGUAGE + "PROGRAMMING-LANGUAGE]...\n"
+ + "[" + PREFIX_PRIORITY + "PRIORITY]\n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_PHONE + "91234567 "
+ PREFIX_EMAIL + "johndoe@example.com";
@@ -94,14 +111,22 @@ public CommandResult execute(Model model) throws CommandException {
*/
private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
assert personToEdit != null;
-
+ CompanyName updatedCompanyName = editPersonDescriptor.getCompanyName().orElse(personToEdit.getCompanyName());
Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
+ InterviewTime updatedDateTime = editPersonDescriptor.getDateTime().orElse(personToEdit.getDateTime());
+ Salary updatedSalary = editPersonDescriptor.getSalary().orElse(personToEdit.getSalary());
+ Info updatedInfo = editPersonDescriptor.getInfo().orElse(personToEdit.getInfo());
Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ Set updatedProgrammingLanguages = editPersonDescriptor.getProgrammingLanguages()
+ .orElse(personToEdit.getProgrammingLanguages());
+ int updatedPriority = editPersonDescriptor.getPriority().orElse(personToEdit.getPriority());
+ return new Person(
+ updatedCompanyName, updatedName, updatedPhone, updatedEmail,
+ updatedAddress, updatedDateTime, updatedSalary, updatedInfo,
+ updatedTags, updatedProgrammingLanguages, updatedPriority);
}
@Override
@@ -116,6 +141,12 @@ public boolean equals(Object other) {
}
EditCommand otherEditCommand = (EditCommand) other;
+ System.out.println("EditCommand equals");
+ System.out.println("index: " + index + " other index: " + ((EditCommand) other).index);
+ System.out.println("editPersonDescriptor: " + editPersonDescriptor + " other editPersonDescriptor: "
+ + ((EditCommand) other).editPersonDescriptor);
+ System.out.println(index.equals(otherEditCommand.index));
+ System.out.println(editPersonDescriptor.equals(otherEditCommand.editPersonDescriptor));
return index.equals(otherEditCommand.index)
&& editPersonDescriptor.equals(otherEditCommand.editPersonDescriptor);
}
@@ -133,11 +164,17 @@ public String toString() {
* corresponding field value of the person.
*/
public static class EditPersonDescriptor {
+ private CompanyName companyName;
private Name name;
private Phone phone;
private Email email;
private Address address;
+ private InterviewTime dateTime;
+ private Salary salary;
+ private Info info;
private Set tags;
+ private Set programmingLanguages;
+ private Integer priority;
public EditPersonDescriptor() {}
@@ -146,23 +183,37 @@ public EditPersonDescriptor() {}
* A defensive copy of {@code tags} is used internally.
*/
public EditPersonDescriptor(EditPersonDescriptor toCopy) {
+ setCompanyName(toCopy.companyName);
setName(toCopy.name);
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
+ setDateTime(toCopy.dateTime);
+ setSalary(toCopy.salary);
+ setInfo(toCopy.info);
setTags(toCopy.tags);
+ setProgrammingLanguages(toCopy.programmingLanguages);
+ setPriority(toCopy.priority);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(companyName, name, phone, email, address, dateTime, salary, info, tags,
+ programmingLanguages, priority);
+ }
+ public void setCompanyName(CompanyName companyName) {
+ this.companyName = companyName;
}
public void setName(Name name) {
this.name = name;
}
+ public Optional getCompanyName() {
+ return Optional.ofNullable(companyName);
+ }
+
public Optional getName() {
return Optional.ofNullable(name);
@@ -187,11 +238,31 @@ public Optional getEmail() {
public void setAddress(Address address) {
this.address = address;
}
+ public void setDateTime(InterviewTime dateTime) {
+ this.dateTime = dateTime;
+ }
+ public Optional getDateTime() {
+ return Optional.ofNullable(dateTime);
+ }
public Optional getAddress() {
return Optional.ofNullable(address);
}
+ public void setSalary(Salary salary) {
+ this.salary = salary;
+ }
+
+ public Optional getSalary() {
+ return Optional.ofNullable(salary);
+ }
+
+ public void setInfo(Info info) {
+ this.info = info; }
+
+ public Optional getInfo() {
+ return Optional.ofNullable(info); }
+
/**
* Sets {@code tags} to this object's {@code tags}.
* A defensive copy of {@code tags} is used internally.
@@ -209,6 +280,33 @@ public Optional> getTags() {
return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
}
+ /**
+ * Sets {@code programmingLanguages} to this object's {@code programmingLanguages}.
+ * A defensive copy of {@code programmingLanguages} is used internally.
+ */
+ public void setProgrammingLanguages(Set programmingLanguages) {
+ this.programmingLanguages = (programmingLanguages != null) ? new HashSet<>(programmingLanguages) : null;
+ }
+
+ /**
+ * Returns an unmodifiable programmingLanguages set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code programmingLanguages} is null.
+ */
+ public Optional> getProgrammingLanguages() {
+ return (programmingLanguages != null) ? Optional.of(Collections
+ .unmodifiableSet(programmingLanguages)) : Optional.empty();
+ }
+
+ public void setPriority(Integer priority) {
+ this.priority = priority;
+ }
+
+ public Optional getPriority() {
+ return Optional.ofNullable(priority);
+ }
+
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -221,22 +319,36 @@ public boolean equals(Object other) {
}
EditPersonDescriptor otherEditPersonDescriptor = (EditPersonDescriptor) other;
- return Objects.equals(name, otherEditPersonDescriptor.name)
+ return Objects.equals(companyName, otherEditPersonDescriptor.companyName)
+ && Objects.equals(name, otherEditPersonDescriptor.name)
&& Objects.equals(phone, otherEditPersonDescriptor.phone)
&& Objects.equals(email, otherEditPersonDescriptor.email)
&& Objects.equals(address, otherEditPersonDescriptor.address)
- && Objects.equals(tags, otherEditPersonDescriptor.tags);
+ && Objects.equals(dateTime, otherEditPersonDescriptor.dateTime)
+ && Objects.equals(salary, otherEditPersonDescriptor.salary)
+ && Objects.equals(info, otherEditPersonDescriptor.info)
+ && Objects.equals(tags, otherEditPersonDescriptor.tags)
+ && Objects.equals(programmingLanguages, otherEditPersonDescriptor.programmingLanguages)
+ && Objects.equals(priority, otherEditPersonDescriptor.priority);
}
@Override
public String toString() {
return new ToStringBuilder(this)
+ .add("company name", companyName)
.add("name", name)
.add("phone", phone)
.add("email", email)
.add("address", address)
+ .add("dateTime", dateTime)
+ .add("salary", salary)
+ .add("info", info)
.add("tags", tags)
+ .add("programmingLanguages", programmingLanguages)
+ .add("priority", priority)
.toString();
}
+
+
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..eb7560413f9 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -13,7 +13,7 @@ public class ExitCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, false, true);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FilterCommand.java b/src/main/java/seedu/address/logic/commands/FilterCommand.java
new file mode 100644
index 00000000000..8caffd490dc
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterCommand.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+
+/**
+ * Abstract class representing a FilterCommand for filtering contacts in an address book.
+ * Subclasses will implement specific filter commands for different categories.
+ */
+public abstract class FilterCommand extends Command {
+
+ public static final String COMMAND_WORD = "filter";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters the contact by various categories and "
+ + "displays them as a list with index numbers.\n"
+ + "Parameters:\n"
+ + "- " + PREFIX_TAG + "TAG [MORE TAG]...\n"
+ + "- " + PREFIX_SALARY + "SALARY_RANGE [MORE SALARY_RANGE]...\n"
+ + "- " + PREFIX_INTERVIEWTIME + "INTERVIEW_TIME_RANGE [MORE INTERVIEW_TIME_RANGE]...\n"
+ + "- " + PREFIX_PROGRAMMING_LANGUAGE
+ + "PROGRAMMING_LANGUAGE [MORE PROGRAMMING_LANGUAGE]...\n"
+ + "Example: " + COMMAND_WORD + " s/2000 5000-7000";
+}
diff --git a/src/main/java/seedu/address/logic/commands/FilterInterviewTimeCommand.java b/src/main/java/seedu/address/logic/commands/FilterInterviewTimeCommand.java
new file mode 100644
index 00000000000..7d76b593ffb
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterInterviewTimeCommand.java
@@ -0,0 +1,73 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.InterviewTime;
+import seedu.address.model.person.InterviewTimeContainsKeywordsPredicate;
+
+
+/**
+ * Filters and lists all contacts in address book whose InterviewTime is within the interview time range provided.
+ */
+public class FilterInterviewTimeCommand extends FilterCommand {
+ public static final String COMMAND_WORD = FilterCommand.COMMAND_WORD + " " + PREFIX_INTERVIEWTIME;
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all companies whose "
+ + "range of interview times contain any of "
+ + "the specified salary and displays them as a list with index numbers.\n"
+ + "Parameters: INTERVIEW_TIME_RANGE [MORE_INTERVIEW_TIME_RANGE]...\n"
+ + "Valid INTERVIEW_TIME_RANGE includes:\n"
+ + "- before/INTERVIEW_TIME\n"
+ + "- after/INTERVIEW_TIME\n"
+ + "- from/INTERVIEW_TIME-INTERVIEW_TIME\n"
+ + "Example:\n"
+ + "- " + COMMAND_WORD + "before/020220241100 after/020220251100 from/030420240800-020520241100";
+ public static final String WRONG_INTERVIEW_TIME_RANGE_MESSAGE = "For INTERVIEW_TIME_RANGE starting with from/ :\n"
+ + " Format: from/INTERVIEW_TIME-INTERVIEW_TIME\n"
+ + " where:\n"
+ + " 1) There are no white spaces before and after '-'\n"
+ + " 2) The first INTERVIEW_TIME provided should be chronologically before or equal to the second "
+ + "INTERVIEW_TIME\n"
+ + " 3) INTERVIEW_TIME is in the form: " + InterviewTime.INTERVIEW_TIME_FORMAT
+ + "\n Example: from/" + InterviewTime.EXAMPLE_INTERVIEW_TIME_FORMAT_1 + "-"
+ + InterviewTime.EXAMPLE_INTERVIEW_TIME_FORMAT_2;
+
+ private final InterviewTimeContainsKeywordsPredicate predicate;
+
+ public FilterInterviewTimeCommand(InterviewTimeContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterInterviewTimeCommand)) {
+ return false;
+ }
+
+ FilterInterviewTimeCommand otherFilterInterviewTimeCommand = (FilterInterviewTimeCommand) other;
+ return predicate.equals(otherFilterInterviewTimeCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("interviewTime", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FilterProgrammingLanguageCommand.java b/src/main/java/seedu/address/logic/commands/FilterProgrammingLanguageCommand.java
new file mode 100644
index 00000000000..d6285157b8e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterProgrammingLanguageCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;
+
+/**
+ * Filters and lists all persons in address book whose programming language contains any of the argument keywords.
+ */
+public class FilterProgrammingLanguageCommand extends FilterCommand {
+
+ public static final String COMMAND_WORD = FilterCommand.COMMAND_WORD + " " + PREFIX_PROGRAMMING_LANGUAGE;
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all contacts whose programming language "
+ + "contain any of the specified tags and displays them as a list with index numbers.\n"
+ + "Parameters: PROGRAMMING_LANGUAGE [MORE_PROGRAMMING_LANGUAGES]...\n"
+ + "Example: " + COMMAND_WORD + " Java";
+
+ private final ProgrammingLanguageContainsKeywordsPredicate predicate;
+
+ public FilterProgrammingLanguageCommand(ProgrammingLanguageContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterProgrammingLanguageCommand)) {
+ return false;
+ }
+
+ FilterProgrammingLanguageCommand otherFindCommand = (FilterProgrammingLanguageCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("programming_language", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FilterSalaryCommand.java b/src/main/java/seedu/address/logic/commands/FilterSalaryCommand.java
new file mode 100644
index 00000000000..c9350391f60
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterSalaryCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+
+
+
+/**
+ * Filters and lists all contacts in address book whose Salary is within the salary range provided.
+ */
+public class FilterSalaryCommand extends FilterCommand {
+ public static final String COMMAND_WORD = FilterCommand.COMMAND_WORD + " " + PREFIX_SALARY;
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all companies whose "
+ + "salary range contain any of "
+ + "the specified salary and displays them as a list with index numbers.\n"
+ + "Parameters: SALARY_RANGE [MORE_SALARY_RANGE]...\n"
+ + "Example: " + COMMAND_WORD + "5000-6000 >=8000";
+
+ private final SalaryContainsKeywordsPredicate predicate;
+
+ public FilterSalaryCommand(SalaryContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterSalaryCommand)) {
+ return false;
+ }
+
+ FilterSalaryCommand otherFindCommand = (FilterSalaryCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("salary", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FilterTagCommand.java b/src/main/java/seedu/address/logic/commands/FilterTagCommand.java
new file mode 100644
index 00000000000..89a70417bf8
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterTagCommand.java
@@ -0,0 +1,60 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+
+/**
+ * Filters and lists all persons in address book whose tags contains any of the argument keywords.
+ */
+public class FilterTagCommand extends FilterCommand {
+
+ public static final String COMMAND_WORD = FilterCommand.COMMAND_WORD + " " + PREFIX_TAG;
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all contacts whose tags contain any of "
+ + "the specified tags and displays them as a list with index numbers.\n"
+ + "Parameters: TAG [MORE_TAGS]...\n"
+ + "Example: " + COMMAND_WORD + " owes money";
+
+ private final TagContainsKeywordsPredicate predicate;
+
+ public FilterTagCommand(TagContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterTagCommand)) {
+ return false;
+ }
+
+ FilterTagCommand otherFindCommand = (FilterTagCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("tag", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..dd34ccc39b2 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -5,24 +5,24 @@
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.NameOrCompanyNameContainsKeywordsPredicate;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
+ * Finds and lists all persons in address book whose name or company name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
*/
public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names or company names contain"
+ + "any of the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
+ + "Example: " + COMMAND_WORD + " alice google";
- private final NameContainsKeywordsPredicate predicate;
+ private final NameOrCompanyNameContainsKeywordsPredicate predicate;
- public FindCommand(NameContainsKeywordsPredicate predicate) {
+ public FindCommand(NameOrCompanyNameContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}
@@ -36,6 +36,7 @@ public CommandResult execute(Model model) {
@Override
public boolean equals(Object other) {
+ assert 1 == 1;
if (other == this) {
return true;
}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..07d26e2a23c 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -16,6 +16,6 @@ public class HelpCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/SortCommand.java b/src/main/java/seedu/address/logic/commands/SortCommand.java
new file mode 100644
index 00000000000..af87a261662
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/SortCommand.java
@@ -0,0 +1,86 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.PersonCompanyNameComparator;
+import seedu.address.model.person.PersonInterviewTimeComparator;
+import seedu.address.model.person.PersonJobDifficultyComparator;
+import seedu.address.model.person.PersonNameComparator;
+import seedu.address.model.person.PersonPriorityComparator;
+import seedu.address.model.person.PersonSalaryComparator;
+
+/**
+ * Sorts the list of contacts based on a specified information.
+ */
+public class SortCommand extends Command {
+
+ public static final String COMMAND_WORD = "sort";
+ public static final Object MESSAGE_USAGE = COMMAND_WORD + ": Sorts the current list of contacts "
+ + "based on a specified information. \n"
+ + "Optional: [rev/] for reverse order\n"
+ + "Parameters: PERSON ATTRIBUTE (only hashable types)"
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY NAME] "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_INTERVIEWTIME + "INTERVIEW-TIME] "
+ + "[" + PREFIX_SALARY + "SALARY] "
+ + "Example: " + COMMAND_WORD + " " + PREFIX_INTERVIEWTIME;
+
+ public static final String MESSAGE_LIST_SORTED_SUCCESS = "List Sorted";
+ private final Integer info;
+ private final boolean isReverseOrder;
+ /**
+ * Creates a SortCommand to sort the list of contacts based on the specified information.
+ */
+ public SortCommand(Integer info, boolean isInverse) {
+ requireNonNull(info);
+ this.info = info;
+ this.isReverseOrder = isInverse;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ switch (info) {
+ case 0:
+ model.updateSortedPersonList(new PersonPriorityComparator(isReverseOrder));
+ break;
+ case 1:
+ model.updateSortedPersonList(new PersonCompanyNameComparator(isReverseOrder));
+ break;
+ case 2:
+ model.updateSortedPersonList(new PersonNameComparator(isReverseOrder));
+ break;
+ case 3:
+ model.updateSortedPersonList(new PersonInterviewTimeComparator(isReverseOrder));
+ break;
+ case 4:
+ model.updateSortedPersonList(new PersonSalaryComparator(isReverseOrder));
+ break;
+ case 5:
+ model.updateSortedPersonList(new PersonJobDifficultyComparator(isReverseOrder));
+ break;
+ default:
+ throw new CommandException(Messages.MESSAGE_INVALID_SORT_COMMAND_INDEX);
+ }
+ return new CommandResult(MESSAGE_LIST_SORTED_SUCCESS);
+ }
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ // instanceof handles nulls
+ if (!(other instanceof SortCommand)) {
+ return false;
+ }
+ SortCommand otherSort = (SortCommand) other;
+ return info.equals(otherSort.info);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..e891b171018 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -2,9 +2,15 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Set;
@@ -12,11 +18,16 @@
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
/**
@@ -31,21 +42,35 @@ public class AddCommandParser implements Parser {
*/
public AddCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(
+ args, PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_INTERVIEWTIME, PREFIX_TAG, PREFIX_SALARY,
+ PREFIX_INFO, PREFIX_PROGRAMMING_LANGUAGE, PREFIX_PRIORITY);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_ADDRESS,
+ PREFIX_PHONE, PREFIX_EMAIL) || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_INTERVIEWTIME, PREFIX_INFO, PREFIX_SALARY, PREFIX_PRIORITY);
+ CompanyName companyName = ParserUtil.parseCompanyName(argMultimap.getValue(PREFIX_COMPANY_NAME).get());
Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
+ InterviewTime interviewTime = ParserUtil.parseInterviewTime(argMultimap.getValue(PREFIX_INTERVIEWTIME)
+ .orElse(null));
+ Salary salary = ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).orElse("0"));
+ Info info = ParserUtil.parseInfo(argMultimap.getValue(PREFIX_INFO).orElse(""));
Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+ Set programmingLanguageList = ParserUtil.parseProgrammingLanguages(argMultimap
+ .getAllValues(PREFIX_PROGRAMMING_LANGUAGE));
+ int priority = ParserUtil.parsePriority(argMultimap.getValue(PREFIX_PRIORITY).orElse("2"));
- Person person = new Person(name, phone, email, address, tagList);
+ Person person = new Person(companyName, name, phone, email, address, interviewTime, salary, info, tagList,
+ programmingLanguageList, priority);
return new AddCommand(person);
}
diff --git a/src/main/java/seedu/address/logic/parser/AddResumeCommandParser.java b/src/main/java/seedu/address/logic/parser/AddResumeCommandParser.java
new file mode 100644
index 00000000000..04466110010
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddResumeCommandParser.java
@@ -0,0 +1,79 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EDUCATION;
+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_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddResumeCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
+import seedu.address.model.person.user.Education;
+import seedu.address.model.person.user.User;
+
+/**
+ * Parses input arguments and creates a new AddResumeCommand object
+ */
+public class AddResumeCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddResumeCommand
+ * and returns an AddResumeCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddResumeCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(
+ args, PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_SALARY, PREFIX_EDUCATION, PREFIX_PROGRAMMING_LANGUAGE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_COMPANY_NAME, PREFIX_SALARY, PREFIX_EDUCATION) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddResumeCommand.MESSAGE_USAGE));
+ }
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_SALARY, PREFIX_EDUCATION);
+ CompanyName companyName = ParserUtil.parseCompanyName(argMultimap.getValue(PREFIX_COMPANY_NAME).get());
+ Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
+ Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
+ Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
+ Salary salary = ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).orElse("0"));
+ Education education = ParserUtil.parseEducation(argMultimap.getValue(PREFIX_EDUCATION).get());
+ Set skills = ParserUtil.parseProgrammingLanguages(argMultimap
+ .getAllValues(PREFIX_PROGRAMMING_LANGUAGE));
+
+ User user = User.getInstance();
+ user.reset();
+ user.setCompanyName(companyName);
+ user.setName(name);
+ user.setPhone(phone);
+ user.setEmail(email);
+ user.setAddress(address);
+ user.setSalary(salary);
+ user.setEducation(education);
+ user.setSkills(skills);
+
+ return new AddResumeCommand(user);
+ }
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 3149ee07e0b..349da8a0cae 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -9,14 +9,17 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddResumeCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.logic.commands.DeleteAbstractCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -42,10 +45,8 @@ public Command parseCommand(String userInput) throws ParseException {
if (!matcher.matches()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
}
-
final String commandWord = matcher.group("commandWord");
final String arguments = matcher.group("arguments");
-
// Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
// log messages such as the one below.
// Lower level log messages are used sparingly to minimize noise in the code.
@@ -59,8 +60,8 @@ public Command parseCommand(String userInput) throws ParseException {
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
+ case DeleteAbstractCommand.COMMAND_WORD:
+ return new DeleteAbstractCommandParser().parse(arguments);
case ClearCommand.COMMAND_WORD:
return new ClearCommand();
@@ -68,6 +69,9 @@ public Command parseCommand(String userInput) throws ParseException {
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
+ case FilterCommand.COMMAND_WORD:
+ return new FilterCommandParser().parse(arguments);
+
case ListCommand.COMMAND_WORD:
return new ListCommand();
@@ -77,6 +81,12 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case SortCommand.COMMAND_WORD:
+ return new SortCommandParser().parse(arguments);
+
+ case AddResumeCommand.COMMAND_WORD:
+ return new AddResumeCommandParser().parse(arguments);
+
default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
index 21e26887a83..9e535355b7d 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
@@ -75,4 +75,8 @@ public void verifyNoDuplicatePrefixesFor(Prefix... prefixes) throws ParseExcepti
throw new ParseException(Messages.getErrorMessageForDuplicatePrefixes(duplicatedPrefixes));
}
}
+
+ public int getSize() {
+ return argMultimap.size();
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..062f3530940 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -10,6 +10,15 @@ public class CliSyntax {
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
+ public static final Prefix PREFIX_COMPANY_NAME = new Prefix("cn/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_INTERVIEWTIME = new Prefix("tt/");
+ public static final Prefix PREFIX_SALARY = new Prefix("s/");
+ public static final Prefix PREFIX_INFO = new Prefix("i/");
+ public static final Prefix PREFIX_PROGRAMMING_LANGUAGE = new Prefix("pl/");
+ public static final Prefix PREFIX_PRIORITY = new Prefix("pri/");
+ public static final Prefix PREFIX_RESUME = new Prefix("resume/");
+ public static final Prefix PREFIX_EDUCATION = new Prefix("edu/");
+ public static final Prefix PREFIX_JOB_DIFFICULTY = new Prefix("jd/");
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteAbstractCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteAbstractCommandParser.java
new file mode 100644
index 00000000000..23f9ee9e0aa
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteAbstractCommandParser.java
@@ -0,0 +1,58 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.DeleteAbstractCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteAbstractCommand object
+ */
+public class DeleteAbstractCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteAbstractCommand
+ * and returns a DeleteAbstractCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteAbstractCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_TAG);
+
+ if (!exactlyOnePrefixPresent(argMultimap, PREFIX_TAG)) {
+ System.out.println("1");
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteAbstractCommand.MESSAGE_USAGE));
+ }
+
+ if (argMultimap.getSize() == 1) {
+ return new DeleteCommandParser().parse(args);
+ } else if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteAbstractCommand.MESSAGE_USAGE));
+ }
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_TAG);
+
+ if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ return new DeleteTagCommandParser().parse(argMultimap.getValue(PREFIX_TAG).get());
+ } else {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteAbstractCommand.MESSAGE_USAGE));
+ }
+ }
+
+ /**
+ * Returns true if exactly one of the prefixes contains a non-empty {@code Optional} value in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean exactlyOnePrefixPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ long count = Stream.of(prefixes)
+ .filter(prefix -> argumentMultimap.getValue(prefix).isPresent())
+ .count();
+ return count <= 1;
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 3527fe76a3e..f124973cb3d 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -25,5 +25,4 @@ public DeleteCommand parse(String args) throws ParseException {
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java
new file mode 100644
index 00000000000..2c0d2564885
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java
@@ -0,0 +1,60 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.logic.commands.DeleteTagCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new DeleteTagCommand object.
+ */
+public class DeleteTagCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteTagCommand
+ * and returns a DeleteTagCommand object for execution.
+ * @throws ParseException if the user input does not conform to the expected format
+ */
+ @Override
+ public DeleteTagCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTagCommand.MESSAGE_USAGE));
+ }
+ String[] tagKeywords = trimmedArgs.split("\\s+");
+ try {
+ List tags = parseTags(tagKeywords);
+ return new DeleteTagCommand(new TagContainsKeywordsPredicate(tags));
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTagCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+ /**
+ * Parses {@code Collection tagNames} into a {@code List}.
+ *
+ * @param tagNames The collection of tag names to parse.
+ * @return A list of parsed tags.
+ * @throws ParseException If any of the tag names are invalid.
+ */
+ public static List parseTags(String... tagNames) throws ParseException {
+ requireNonNull(tagNames);
+ List parsedTags = new ArrayList<>();
+ for (String tagName : tagNames) {
+ try {
+ parsedTags.add(ParserUtil.parseTag(tagName));
+ } catch (ParseException pe) {
+ throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ }
+ }
+ return parsedTags;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..43b75d8086e 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -3,9 +3,15 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Collection;
@@ -17,6 +23,7 @@
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.tag.Tag;
/**
@@ -27,25 +34,33 @@ public class EditCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the EditCommand
* and returns an EditCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(
+ args, PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_INTERVIEWTIME, PREFIX_SALARY, PREFIX_INFO,
+ PREFIX_TAG, PREFIX_PROGRAMMING_LANGUAGE, PREFIX_PRIORITY);
Index index;
-
try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(
+ PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_SALARY, PREFIX_INFO,
+ PREFIX_ADDRESS, PREFIX_INTERVIEWTIME, PREFIX_PRIORITY);
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
-
+ if (argMultimap.getValue(PREFIX_COMPANY_NAME).isPresent()) {
+ editPersonDescriptor.setCompanyName(ParserUtil.parseCompanyName(
+ argMultimap.getValue(PREFIX_COMPANY_NAME).get()));
+ }
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
}
@@ -58,15 +73,28 @@ public EditCommand parse(String args) throws ParseException {
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
+ if (argMultimap.getValue(PREFIX_INTERVIEWTIME).isPresent()) {
+ editPersonDescriptor.setDateTime(
+ ParserUtil.parseInterviewTime(argMultimap.getValue(PREFIX_INTERVIEWTIME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_SALARY).isPresent()) {
+ editPersonDescriptor.setSalary(ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).get()));
+ }
+ if (argMultimap.getValue(PREFIX_INFO).isPresent()) {
+ editPersonDescriptor.setInfo(ParserUtil.parseInfo(argMultimap.getValue(PREFIX_INFO).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PRIORITY).isPresent()) {
+ editPersonDescriptor.setPriority(ParserUtil.parsePriority(argMultimap.getValue(PREFIX_PRIORITY).get()));
+ }
parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
+ parseProgrammingLanguagesForEdit(argMultimap.getAllValues(PREFIX_PROGRAMMING_LANGUAGE))
+ .ifPresent(editPersonDescriptor::setProgrammingLanguages);
if (!editPersonDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
-
return new EditCommand(index, editPersonDescriptor);
}
-
/**
* Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
* If {@code tags} contain only one element which is an empty string, it will be parsed into a
@@ -82,4 +110,25 @@ private Optional> parseTagsForEdit(Collection tags) throws Pars
return Optional.of(ParserUtil.parseTags(tagSet));
}
+ /**
+ * Parses a collection of programming language names into a set of ProgrammingLanguages if the collection is
+ * non-empty. If the collection contains only one element which is an empty string, it will be parsed into a
+ * set containing zero programming languages.
+ *
+ * @param programmingLanguages A collection of programming language names to be parsed.
+ * @return An Optional containing set of ProgrammingLanguages if collection is non-empty, otherwise empty Optional.
+ * @throws ParseException If any of the programming language names is invalid.
+ */
+ private Optional> parseProgrammingLanguagesForEdit(Collection programmingLanguages)
+ throws ParseException {
+ assert programmingLanguages != null;
+
+ if (programmingLanguages.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection languageSet = programmingLanguages.size() == 1 && programmingLanguages.contains("")
+ ? Collections.emptySet() : programmingLanguages;
+ return Optional.of(ParserUtil.parseProgrammingLanguages(languageSet));
+ }
+
}
diff --git a/src/main/java/seedu/address/logic/parser/FilterCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterCommandParser.java
new file mode 100644
index 00000000000..0657867cc39
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterCommandParser.java
@@ -0,0 +1,61 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.FilterCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+
+/**
+ * Parses input arguments and creates a new FilterCommand object
+ */
+public class FilterCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterCommand
+ * and returns a FilterCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(
+ args, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME, PREFIX_PROGRAMMING_LANGUAGE);
+ if (!exactlyOnePrefixPresent(argMultimap, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME,
+ PREFIX_PROGRAMMING_LANGUAGE) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
+ }
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME,
+ PREFIX_PROGRAMMING_LANGUAGE);
+
+ if (argMultimap.getValue(PREFIX_SALARY).isPresent()) {
+ return new FilterSalaryCommandParser().parse(argMultimap.getValue(PREFIX_SALARY).get());
+ } else if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ return new FilterTagCommandParser().parse(argMultimap.getValue(PREFIX_TAG).get());
+ } else if (argMultimap.getValue(PREFIX_PROGRAMMING_LANGUAGE).isPresent()) {
+ return new FilterProgrammingLanguageCommandParser().parse(argMultimap.getValue(PREFIX_PROGRAMMING_LANGUAGE)
+ .get());
+ } else {
+ return new FilterInterviewTimeCommandParser().parse(argMultimap.getValue(PREFIX_INTERVIEWTIME).get());
+ }
+ }
+
+ /**
+ * Returns true if at least one of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean exactlyOnePrefixPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ long count = Stream.of(prefixes)
+ .filter(prefix -> argumentMultimap.getValue(prefix).isPresent())
+ .count();
+ return count == 1;
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/FilterInterviewTimeCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterInterviewTimeCommandParser.java
new file mode 100644
index 00000000000..c32bbda7f15
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterInterviewTimeCommandParser.java
@@ -0,0 +1,98 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import seedu.address.logic.commands.FilterInterviewTimeCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.InterviewTime;
+import seedu.address.model.person.InterviewTimeContainsKeywordsPredicate;
+
+
+/**
+ * Parses input arguments and creates a new FilterInterviewCommand object
+ */
+public class FilterInterviewTimeCommandParser {
+ private static final Prefix PREFIX_BEFORE_INTERVIEW_TIME = new Prefix("before/");
+ private static final Prefix PREFIX_AFTER_INTERVIEW_TIME = new Prefix("after/");
+ private static final Prefix PREFIX_FROM_INTERVIEW_TIME = new Prefix("from/");
+ private static final String VALIDATION_REGEX_FROM_PREFIX = "^[^-]*-[^-]*$";
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterInterviewTimeCommand
+ * and returns a FilterInterviewTimeCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterInterviewTimeCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterInterviewTimeCommand.MESSAGE_USAGE));
+ }
+ trimmedArgs = " " + trimmedArgs;
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(
+ trimmedArgs, PREFIX_BEFORE_INTERVIEW_TIME, PREFIX_AFTER_INTERVIEW_TIME,
+ PREFIX_FROM_INTERVIEW_TIME);
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterInterviewTimeCommand.MESSAGE_USAGE));
+ }
+ List> interviewTimes = new ArrayList<>();
+ if (argMultimap.getValue(PREFIX_BEFORE_INTERVIEW_TIME).isPresent()) {
+ interviewTimes.addAll(handleBeforeInterviewTime(argMultimap));
+ }
+ if (argMultimap.getValue(PREFIX_AFTER_INTERVIEW_TIME).isPresent()) {
+ interviewTimes.addAll(handleAfterInterviewTime(argMultimap));
+ }
+ if (argMultimap.getValue(PREFIX_FROM_INTERVIEW_TIME).isPresent()) {
+ interviewTimes.addAll(handleFromInterviewTime(argMultimap));
+ }
+ return new FilterInterviewTimeCommand(new InterviewTimeContainsKeywordsPredicate(interviewTimes));
+ }
+ private static List> handleFromInterviewTime(ArgumentMultimap argMultimap)
+ throws ParseException {
+ List rangeInterviewTimes = argMultimap.getAllValues(PREFIX_FROM_INTERVIEW_TIME);
+ List> interviewTimes = new ArrayList<>();
+ for (String rangeInterviewTime : rangeInterviewTimes) {
+ if (!rangeInterviewTime.matches(VALIDATION_REGEX_FROM_PREFIX)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterInterviewTimeCommand.WRONG_INTERVIEW_TIME_RANGE_MESSAGE));
+ } else {
+ String[] range = rangeInterviewTime.split("-");
+ List rangeTimes = new ArrayList<>();
+ for (String interviewTime : range) {
+ rangeTimes.add(ParserUtil.parseInterviewTime(interviewTime));
+ }
+ if (rangeTimes.get(1).isBefore(rangeTimes.get(0))) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterInterviewTimeCommand.WRONG_INTERVIEW_TIME_RANGE_MESSAGE));
+ }
+ interviewTimes.add(rangeTimes);
+ }
+ }
+ return interviewTimes;
+ }
+ private static List> handleBeforeInterviewTime(ArgumentMultimap argMultimap)
+ throws ParseException {
+ List beforeInterviewTimes = argMultimap.getAllValues(PREFIX_BEFORE_INTERVIEW_TIME);
+ List> interviewTimes = new ArrayList<>();
+ for (String beforeInterviewTime : beforeInterviewTimes) {
+ interviewTimes.add(Arrays.asList(null, ParserUtil.parseInterviewTime(beforeInterviewTime)));
+ }
+ return interviewTimes;
+ }
+ private static List> handleAfterInterviewTime(ArgumentMultimap argMultimap)
+ throws ParseException {
+ List afterInterviewTimes = argMultimap.getAllValues(PREFIX_AFTER_INTERVIEW_TIME);
+ List> interviewTimes = new ArrayList<>();
+ for (String afterInterviewTime : afterInterviewTimes) {
+ interviewTimes.add(Arrays.asList(ParserUtil.parseInterviewTime(afterInterviewTime), null));
+ }
+ return interviewTimes;
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParser.java
new file mode 100644
index 00000000000..c4e0c36d452
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParser.java
@@ -0,0 +1,43 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.logic.commands.FilterProgrammingLanguageCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
+import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindCommand object
+ */
+public class FilterProgrammingLanguageCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterProgrammingLanguageCommand
+ * and returns a FilterProgrammingLanguageCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterProgrammingLanguageCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterProgrammingLanguageCommand.MESSAGE_USAGE));
+ }
+ String[] languageKeywords = trimmedArgs.split("\\s+");
+ return new FilterProgrammingLanguageCommand(
+ new ProgrammingLanguageContainsKeywordsPredicate(createLanguages(languageKeywords)));
+ }
+
+ /**
+ * Parses {@code languageKeywords} into a {@code List}.
+ */
+ public static List createLanguages(String... languageKeywords) throws ParseException {
+ List languages = new ArrayList<>();
+ for (String keyword : languageKeywords) {
+ languages.add(ParserUtil.parseProgrammingLanguage(keyword.toLowerCase())); // Convert to lowercase
+ }
+ return languages;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FilterSalaryCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterSalaryCommandParser.java
new file mode 100644
index 00000000000..d1e8e17de34
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterSalaryCommandParser.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.FilterSalaryCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryRange;
+
+
+/**
+ * Parses input arguments and creates a new FindSalaryCommand object
+ */
+public class FilterSalaryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterSalaryCommand
+ * and returns a FilterSalaryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterSalaryCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterSalaryCommand.MESSAGE_USAGE));
+ }
+
+ String[] salaryKeywords = trimmedArgs.split("\\s+");
+ SalaryRange[] salaries = new SalaryRange[salaryKeywords.length];
+ for (int i = 0; i < salaryKeywords.length; i++) {
+ salaries[i] = ParserUtil.parseSalaryRange(salaryKeywords[i]);
+ }
+ return new FilterSalaryCommand(new SalaryContainsKeywordsPredicate(Arrays.asList(salaries)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FilterTagCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterTagCommandParser.java
new file mode 100644
index 00000000000..da3a5a01bfb
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterTagCommandParser.java
@@ -0,0 +1,45 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.logic.commands.FilterTagCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+
+/**
+ * Parses input arguments and creates a new FilterTagCommand object
+ */
+public class FilterTagCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterTagCommand
+ * and returns a FilterTagCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterTagCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterTagCommand.MESSAGE_USAGE));
+ }
+ String[] tagKeywords = trimmedArgs.split("\\s+");
+ return new FilterTagCommand(new TagContainsKeywordsPredicate(createTags(tagKeywords)));
+ }
+
+ /**
+ * Parses {@code tagKeywords} into a {@code List}.
+ */
+ public static List createTags(String... tagKeywords) throws ParseException {
+ List tags = new ArrayList<>();
+ for (String keyword : tagKeywords) {
+ tags.add(ParserUtil.parseTag(keyword));
+ }
+ return tags;
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..a2b71408413 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -6,7 +6,7 @@
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.NameOrCompanyNameContainsKeywordsPredicate;
/**
* Parses input arguments and creates a new FindCommand object
@@ -25,9 +25,10 @@ public FindCommand parse(String args) throws ParseException {
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ String[] nameOrCompanyNameKeywords = trimmedArgs.split("\\s+");
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ return new FindCommand(new NameOrCompanyNameContainsKeywordsPredicate(
+ Arrays.asList(nameOrCompanyNameKeywords)));
}
}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..0d4c520219f 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -9,10 +9,17 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
+import seedu.address.model.person.SalaryRange;
+import seedu.address.model.person.user.Education;
import seedu.address.model.tag.Tag;
/**
@@ -35,6 +42,36 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException {
return Index.fromOneBased(Integer.parseInt(trimmedIndex));
}
+ /**
+ * Parses a {@code String name} into a {@code Name}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code name} is invalid.
+ */
+ public static CompanyName parseCompanyName(String companyName) throws ParseException {
+ requireNonNull(companyName);
+ String trimmedName = companyName.trim();
+ if (!CompanyName.isValidCompanyName(trimmedName)) {
+ throw new ParseException(CompanyName.MESSAGE_CONSTRAINTS);
+ }
+ return new CompanyName(trimmedName);
+ }
+
+ /**
+ * Parses a {@code String name} into a {@code Name}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code name} is invalid.
+ */
+ public static Education parseEducation(String education) throws ParseException {
+ requireNonNull(education);
+ String trimmedEducation = education.trim();
+ if (!Education.isValidEducation(trimmedEducation)) {
+ throw new ParseException(Education.MESSAGE_CONSTRAINTS);
+ }
+ return new Education(education);
+ }
+
/**
* Parses a {@code String name} into a {@code Name}.
* Leading and trailing whitespaces will be trimmed.
@@ -110,6 +147,24 @@ public static Tag parseTag(String tag) throws ParseException {
return new Tag(trimmedTag);
}
+ /**
+ * Reads the input for interview-time tag
+ * @param dateTime given
+ * @return trimmed output to be stored
+ * @throws ParseException if invalid format
+ */
+ public static InterviewTime parseInterviewTime(String dateTime) throws ParseException {
+ if (dateTime == null) {
+ return new InterviewTime(null);
+ } else {
+ String trimmedDateTime = dateTime.trim();
+ if (!InterviewTime.isValidInterviewTime(trimmedDateTime)) {
+ throw new ParseException(InterviewTime.MESSAGE_CONSTRAINTS);
+ }
+ return new InterviewTime(trimmedDateTime);
+ }
+ }
+
/**
* Parses {@code Collection tags} into a {@code Set}.
*/
@@ -121,4 +176,107 @@ public static Set parseTags(Collection tags) throws ParseException
}
return tagSet;
}
+
+ /**
+ * Parses a {@code String salary} into an {@code Salary}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code salary} is invalid.
+ */
+ public static Salary parseSalary(String salary) throws ParseException {
+ requireNonNull(salary);
+ String trimmedSalary = salary.trim();
+ if (!Salary.isValidSalary(trimmedSalary)) {
+ throw new ParseException(Salary.MESSAGE_CONSTRAINTS);
+ }
+ return new Salary(trimmedSalary);
+ }
+
+ /**
+ * Parses a {@code String salary range} into an {@code Salary}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code salary range} is invalid.
+ */
+ public static SalaryRange parseSalaryRange(String salaryRange) throws ParseException {
+ requireNonNull(salaryRange);
+ String trimmedSalaryRange = salaryRange.trim();
+ if (!SalaryRange.isValidSalaryRange(trimmedSalaryRange)) {
+ throw new ParseException(SalaryRange.MESSAGE_CONSTRAINTS);
+ }
+ return new SalaryRange(trimmedSalaryRange);
+ }
+
+ /**
+ * Parses a {@code String info} into an {@code Info}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Info parseInfo(String info) {
+ String trimmedInfo = info.trim();
+ return new Info(trimmedInfo);
+ }
+
+ /**
+ * Parses a string representing a programming language into a {@code ProgrammingLanguage} object.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param programmingLanguageString A string representing a programming language.
+ * @return A {@code ProgrammingLanguage} object parsed from the input string.
+ * @throws ParseException if the given {@code programmingLanguageString} is invalid.
+ */
+ public static ProgrammingLanguage parseProgrammingLanguage(String programmingLanguageString) throws ParseException {
+ requireNonNull(programmingLanguageString);
+ String trimmedProgrammingLanguage = programmingLanguageString.trim();
+ if (!ProgrammingLanguage.isValidLanguageName(trimmedProgrammingLanguage)) {
+ throw new ParseException(ProgrammingLanguage.MESSAGE_CONSTRAINTS);
+ }
+ return new ProgrammingLanguage(trimmedProgrammingLanguage);
+ }
+
+ /**
+ * Parses collection of strings representing programming languages into set of {@code ProgrammingLanguage} objects.
+ *
+ * @param programmingLanguages A collection of strings representing programming languages.
+ * @return A set of {@code ProgrammingLanguage} objects parsed from the input collection.
+ * @throws ParseException if any of the programming language strings are invalid.
+ */
+ public static Set parseProgrammingLanguages(Collection programmingLanguages)
+ throws ParseException {
+ requireNonNull(programmingLanguages);
+ final Set programmingLanguageSet = new HashSet<>();
+ for (String programmingLanguage : programmingLanguages) {
+ programmingLanguageSet.add(parseProgrammingLanguage(programmingLanguage));
+ }
+ return programmingLanguageSet;
+ }
+
+ /**
+ * Parses a string representing a priority into an integer.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param priority A string representing a priority.
+ * @return An integer parsed from the input string.
+ * @throws ParseException if the given {@code priority} is invalid.
+ */
+ public static Integer parsePriority(String priority) throws ParseException {
+ requireNonNull(priority);
+ String trimmedPriority = priority.trim();
+ if (!trimmedPriority.matches("\\d+")) {
+ throw new ParseException("Priority should be a number between 0 and 4.");
+ }
+ int priorityValue = Integer.parseInt(trimmedPriority);
+ if (priorityValue < 0 || priorityValue > 4) {
+ throw new ParseException("Priority should be a number between 0 and 4.");
+ }
+ return priorityValue;
+ }
+
+ /**
+ * Returns true if a given string is a valid priority.
+ */
+ private static boolean isValidPriority(String test) {
+ String validRegex = "^[0-4]$";
+ return test.matches(validRegex);
+ }
+
}
diff --git a/src/main/java/seedu/address/logic/parser/SortCommandParser.java b/src/main/java/seedu/address/logic/parser/SortCommandParser.java
new file mode 100644
index 00000000000..b42d922abe4
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/SortCommandParser.java
@@ -0,0 +1,81 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_DIFFICULTY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+
+import java.util.Objects;
+
+import seedu.address.logic.commands.SortCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new SortCommand object
+ */
+public class SortCommandParser implements Parser {
+ public static final String MESSAGE_INVALID_COMMAND_LENGTH = "Invalid command length for sort command"
+ + "sort command only accepts 1 arguments";
+ public static final String MESSAGE_INVALID_COMMAND_KEYWORD = "Invalid command keyword for sort command";
+ public static final String MESSAGE_INVALID_INVERSE_COMMAND_KEYWORD = "Invalid command keyword for sort command, "
+ + "more than 1 keywords detected or do you mean [rev/] [keyword]?";
+ private boolean isReverseOrder = false;
+ /**
+ * Parses the given {@code String} of arguments in the context of the SortCommand
+ * and returns a SortCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public SortCommand parse(String args) throws ParseException {
+ Integer index = null;
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
+ }
+
+ String[] inputString = trimmedArgs.split("\\s+");
+
+ if (inputString.length == 1) {
+ isReverseOrder = false;
+ } else if (inputString.length == 2) {
+ if (inputString[0].equalsIgnoreCase("rev/")) {
+ isReverseOrder = true;
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_INVERSE_COMMAND_KEYWORD, SortCommand.MESSAGE_USAGE));
+ }
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_LENGTH, SortCommand.MESSAGE_USAGE));
+ }
+
+ String keyword = null;
+
+ if (isReverseOrder) {
+ keyword = inputString[1];
+ } else {
+ keyword = inputString[0];
+ }
+
+ if (Objects.equals(keyword, PREFIX_PRIORITY.getPrefix())) {
+ index = 0;
+ } else if (Objects.equals(keyword, PREFIX_COMPANY_NAME.getPrefix())) {
+ index = 1;
+ } else if (Objects.equals(keyword, PREFIX_NAME.getPrefix())) {
+ index = 2;
+ } else if (Objects.equals(keyword, PREFIX_INTERVIEWTIME.getPrefix())) {
+ index = 3;
+ } else if (Objects.equals(keyword, PREFIX_SALARY.getPrefix())) {
+ index = 4;
+ } else if (Objects.equals(keyword, PREFIX_JOB_DIFFICULTY.getPrefix())) {
+ index = 5;
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_KEYWORD, SortCommand.MESSAGE_USAGE));
+ }
+ return new SortCommand(index, isReverseOrder);
+ }
+}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 73397161e84..59e123dbc2f 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -2,6 +2,7 @@
import static java.util.Objects.requireNonNull;
+import java.util.Comparator;
import java.util.List;
import javafx.collections.ObservableList;
@@ -86,6 +87,10 @@ public void setPerson(Person target, Person editedPerson) {
persons.setPerson(target, editedPerson);
}
+ public void sortPerosns(Comparator comparator) {
+ persons.sortPersonsList(comparator);
+ }
+
/**
* Removes {@code key} from this {@code AddressBook}.
* {@code key} must exist in the address book.
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..2c07bdf5c48 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -1,6 +1,7 @@
package seedu.address.model;
import java.nio.file.Path;
+import java.util.Comparator;
import java.util.function.Predicate;
import javafx.collections.ObservableList;
@@ -84,4 +85,10 @@ public interface Model {
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate predicate);
+
+ /**
+ * Updates the filter of the filtered person list to filter by the given {@code Prefix}.
+ * @throws NullPointerException if {@code Prefix} is null.
+ */
+ void updateSortedPersonList(Comparator comparator);
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 57bc563fde6..1142ad48de1 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -4,11 +4,13 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.nio.file.Path;
+import java.util.Comparator;
import java.util.function.Predicate;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
+import javafx.collections.transformation.SortedList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
@@ -22,6 +24,7 @@ public class ModelManager implements Model {
private final AddressBook addressBook;
private final UserPrefs userPrefs;
private final FilteredList filteredPersons;
+ private final SortedList sortedPersons;
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
@@ -34,6 +37,7 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ sortedPersons = new SortedList<>(this.addressBook.getPersonList());
}
public ModelManager() {
@@ -127,6 +131,12 @@ public void updateFilteredPersonList(Predicate predicate) {
requireNonNull(predicate);
filteredPersons.setPredicate(predicate);
}
+ //=========== Sorted Person List Accessors =============================================================
+ @Override
+ public void updateSortedPersonList(Comparator info) {
+ requireAllNonNull(info);
+ addressBook.sortPerosns(info);
+ }
@Override
public boolean equals(Object other) {
@@ -142,7 +152,12 @@ public boolean equals(Object other) {
ModelManager otherModelManager = (ModelManager) other;
return addressBook.equals(otherModelManager.addressBook)
&& userPrefs.equals(otherModelManager.userPrefs)
- && filteredPersons.equals(otherModelManager.filteredPersons);
+ && filteredPersons.equals(otherModelManager.filteredPersons)
+ && sortedPersons.equals(otherModelManager.sortedPersons);
}
+ @Override
+ public String toString() {
+ return String.format("%s, %s, %s", this.addressBook, this.userPrefs, this.filteredPersons, this.sortedPersons);
+ }
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 6be655fb4c7..9052661d549 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/address/model/UserPrefs.java
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path addressBookFilePath = Paths.get("data" , "ccbot.json");
/**
* Creates a {@code UserPrefs} with default values.
diff --git a/src/main/java/seedu/address/model/language/ProgrammingLanguage.java b/src/main/java/seedu/address/model/language/ProgrammingLanguage.java
new file mode 100644
index 00000000000..f1989718a0a
--- /dev/null
+++ b/src/main/java/seedu/address/model/language/ProgrammingLanguage.java
@@ -0,0 +1,77 @@
+package seedu.address.model.language;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Programming Language in the address book.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidLanguageName(String)}
+ */
+public class ProgrammingLanguage {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Programming Languages should be alphanumeric and may contain some special characters (+ and #)"
+ + ", and must be less than 50 characters";
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}+#\\s]{1,50}";
+ public final String languageName;
+
+ /**
+ * Constructs a {@code ProgrammingLanguage}.
+ *
+ * @param languageName A valid programming language name.
+ */
+ public ProgrammingLanguage(String languageName) {
+ requireNonNull(languageName);
+ checkArgument(isValidLanguageName(languageName), MESSAGE_CONSTRAINTS);
+ this.languageName = languageName;
+ }
+
+ /**
+ * Returns the name of this programming language.
+ *
+ * @return The name of this programming language.
+ */
+ public String getLanguageName() {
+ return languageName;
+ }
+
+ /**
+ * Returns true if a given string is a valid programming language name.
+ *
+ * @param test The string to test for validity.
+ * @return {@code true} if the string is a valid programming language name, {@code false} otherwise.
+ */
+ public static boolean isValidLanguageName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ProgrammingLanguage)) {
+ return false;
+ }
+
+ ProgrammingLanguage otherLanguage = (ProgrammingLanguage) other;
+ return languageName.equals(otherLanguage.languageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return languageName.hashCode();
+ }
+
+ /**
+ * Returns the string representation of this programming language.
+ *
+ * @return The string representation of this programming language.
+ */
+ @Override
+ public String toString() {
+ return "[" + languageName + "]";
+ }
+}
diff --git a/src/main/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..e1d6690aecc
--- /dev/null
+++ b/src/main/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicate.java
@@ -0,0 +1,66 @@
+package seedu.address.model.language;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.person.Person;
+
+/**
+ * Tests that a {@code Person}'s {@code Tag} matches any of the keywords given.
+ */
+public class ProgrammingLanguageContainsKeywordsPredicate implements Predicate {
+ private final List originalLanguages;
+ private final List lowercaseLanguageNames;
+ /**
+ * Constructs a {@code ProgrammingLanguageContainsKeywordsPredicate} with the given list of programming languages.
+ * Creates two lists: one to store the original ProgrammingLanguage objects and another to store their lowercase
+ * string representations.
+ *
+ * @param languages The list of programming languages to be used in the predicate.
+ * @throws NullPointerException if {@code languages} is null.
+ */
+ public ProgrammingLanguageContainsKeywordsPredicate(List languages) {
+ requireNonNull(languages);
+ this.originalLanguages = new ArrayList<>(languages);
+ this.lowercaseLanguageNames = languages.stream()
+ .map(ProgrammingLanguage::getLanguageName)
+ .map(String::toLowerCase)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean test(Person person) {
+ Set personProgrammingLanguages = person.getProgrammingLanguages();
+ return personProgrammingLanguages.stream()
+ .map(ProgrammingLanguage::getLanguageName)
+ .map(String::toLowerCase)
+ .anyMatch(lowercaseLanguageNames::contains);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ProgrammingLanguageContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ ProgrammingLanguageContainsKeywordsPredicate otherProgrammingLanguageContainsKeywordsPredicate =
+ (ProgrammingLanguageContainsKeywordsPredicate) other;
+ return originalLanguages.equals(otherProgrammingLanguageContainsKeywordsPredicate.originalLanguages);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("programming_language", originalLanguages).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/CompanyName.java b/src/main/java/seedu/address/model/person/CompanyName.java
new file mode 100644
index 00000000000..2a18f8a5518
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/CompanyName.java
@@ -0,0 +1,67 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Company's name in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidCompanyName(String)}
+ */
+public class CompanyName {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Company names should be less than 100 chracters, and it should not be blank";
+
+ /*
+ * The first character of the address must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[^\\s].*";
+
+ public final String companyName;
+
+ /**
+ * Constructs a {@code CompanyName}.
+ *
+ * @param name A valid name.
+ */
+ public CompanyName(String name) {
+ requireNonNull(name);
+ checkArgument(isValidCompanyName(name), MESSAGE_CONSTRAINTS);
+ companyName = name;
+ }
+
+ /**
+ * Returns true if a given string is a valid company name.
+ */
+ public static boolean isValidCompanyName(String test) {
+ return test.length() <= 100 && test.matches(VALIDATION_REGEX);
+ }
+
+
+ @Override
+ public String toString() {
+ return companyName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof CompanyName)) {
+ return false;
+ }
+
+ CompanyName otherName = (CompanyName) other;
+ return companyName.equals(otherName.companyName);
+ }
+
+ @Override
+ public int hashCode() {
+ return companyName.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Info.java b/src/main/java/seedu/address/model/person/Info.java
new file mode 100644
index 00000000000..cc83b63d050
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Info.java
@@ -0,0 +1,65 @@
+package seedu.address.model.person;
+
+/**
+ * Represents a Person's info in the address book.
+ */
+public class Info {
+ public final String value;
+
+ /**
+ * Constructs a {@code Info}.
+ *
+ * @param info Information about the person in the address book
+ */
+ public Info(String info) {
+ String curr = info.trim();
+ if (curr.length() == 0) {
+ value = "No additional info";
+ } else {
+ value = curr;
+ }
+ }
+
+
+ public Info() {
+ value = "No additional info";
+ }
+
+ public static boolean isValidInfo(String test) {
+ return true;
+ }
+
+ public String getInfo() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+
+ if (value.length() == 0) {
+ return "No additional info";
+ }
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Info)) {
+ return false;
+ }
+
+ Info otherInfo = (Info) other;
+ return value.equals(otherInfo.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/InterviewTime.java b/src/main/java/seedu/address/model/person/InterviewTime.java
new file mode 100644
index 00000000000..c3a643b04b2
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/InterviewTime.java
@@ -0,0 +1,124 @@
+package seedu.address.model.person;
+
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Logic to interpret date and time from user input
+ */
+public class InterviewTime {
+
+ public static final String MESSAGE_CONSTRAINTS = "Error thrown, date and time format may be wrong. Check UG.";
+
+ public static final String REGEX_YYYY = "\"([1-9]\\\\d{3}|0\\\\d{3})\"";
+ public static final String REGEX_DD = "(0[1-9]|[1-2][0-9]|3[01])";
+ public static final String REGEX_MM = "(0[1-9]|1[0-2])";
+ public static final String REGEX_HHMM = "^([0-1][0-9]|2[0-3])[0-5][0-9]$";
+ public static final String INTERVIEW_TIME_FORMAT = "ddMMyyyyHHmm";
+ public static final String EXAMPLE_INTERVIEW_TIME_FORMAT_1 = "020520240800";
+ public static final String EXAMPLE_INTERVIEW_TIME_FORMAT_2 = "030820242300";
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(INTERVIEW_TIME_FORMAT); //set format
+
+ public final LocalDateTime dateTime;
+
+ /**
+ * Constructs InterviewTime object
+ * @param dateTime input
+ */
+ public InterviewTime(String dateTime) {
+ if (dateTime == null) {
+ this.dateTime = null;
+ } else {
+ checkArgument(isValidInterviewTime(dateTime), MESSAGE_CONSTRAINTS);
+ this.dateTime = LocalDateTime.parse(dateTime, formatter); //set format
+ }
+ }
+
+ /**
+ * Checks if date input is valid
+ * @param test input
+ * @return true if correct format, false otherwise
+ */
+ public static boolean isValidInterviewTime(String test) {
+ if (test == null) {
+ return true;
+ } else {
+ try {
+ LocalDateTime.parse(test, formatter);
+ return true;
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ }
+ }
+
+ public LocalDateTime getDateTime() {
+ return this.dateTime;
+ }
+
+ public String rawToString() {
+ return dateTime == null ? null : dateTime.format(formatter);
+ }
+
+ /**
+ * Returns true if {@code this.dateTime} is within the range provided.
+ * @param range A List containing two {@code InterviewTime}.
+ */
+ public boolean isWithinInterviewTimeRange(List range) {
+ assert range.size() == 2 : "InterviewTime range should be of size 2";
+ assert !(range.get(0) == null && range.get(1) == null)
+ : "InterviewTime range cannot cannot contain more than 1 null Object";
+ LocalDateTime after = range.get(0) == null ? null : range.get(0).getDateTime();
+ LocalDateTime before = range.get(1) == null ? null : range.get(1).getDateTime();
+ if (after == null) {
+ return this.dateTime.isBefore(before);
+ } else if (before == null) {
+ return this.dateTime.isAfter(after);
+ } else {
+ return (this.dateTime.isBefore(before) || this.dateTime.isEqual(before))
+ && (this.dateTime.isAfter(after) || this.dateTime.isEqual(after));
+ }
+ }
+
+ public boolean isBefore(InterviewTime date) {
+ return this.dateTime.isBefore(date.getDateTime());
+ }
+
+ @Override
+ public String toString() {
+ if (dateTime == null) {
+ return "No Interviews set";
+ } else {
+ DateTimeFormatter beautify = DateTimeFormatter.ofPattern("MMMM dd, yyyy hh:mm a", Locale.ENGLISH);
+ return dateTime.format(beautify);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InterviewTime)) {
+ return false;
+ }
+
+ InterviewTime otherDateTime = (InterviewTime) other;
+ return (dateTime == null && otherDateTime.dateTime == null)
+ || (dateTime != null && dateTime.equals(otherDateTime.dateTime));
+ }
+
+ @Override
+ public int hashCode() {
+ return dateTime == null ? 0 : dateTime.hashCode();
+ }
+
+
+}
diff --git a/src/main/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..435477f6492
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicate.java
@@ -0,0 +1,47 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+
+
+/**
+ * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ */
+public class InterviewTimeContainsKeywordsPredicate implements Predicate {
+ private final List> keywords;
+
+ public InterviewTimeContainsKeywordsPredicate(List> keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(interviewTimeRange -> person.getDateTime().isWithinInterviewTimeRange(interviewTimeRange));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InterviewTimeContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ InterviewTimeContainsKeywordsPredicate otherSalaryContainsKeywordsPredicate =
+ (InterviewTimeContainsKeywordsPredicate) other;
+ return keywords.equals(otherSalaryContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("interviewTimes", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/JobDifficulty.java b/src/main/java/seedu/address/model/person/JobDifficulty.java
new file mode 100644
index 00000000000..7112f62c122
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/JobDifficulty.java
@@ -0,0 +1,53 @@
+package seedu.address.model.person;
+
+import java.util.Random;
+
+/**
+ * Calculate the difficulty of a job in the address book.
+ */
+public class JobDifficulty {
+ private int difficulty = 0;
+
+ /**
+ * Constructs a {@code JobDifficulty}.
+ * The difficulty is calculated based on the company name and salary.
+ *
+ * @param companyName A valid company name.
+ * @param salary A valid salary.
+ */
+ public JobDifficulty(CompanyName companyName, Salary salary) {
+ Random random = new Random();
+ String companyNameString = companyName.toString().toLowerCase();
+ int salaryInt = salary.getSalary1();
+ if (JobDifficultyCompanyList.getJobDifficultyCompanyList().containsKey(companyNameString)) {
+ difficulty += JobDifficultyCompanyList.getJobDifficultyCompanyList().get(companyNameString);
+ } else {
+ difficulty += random.nextInt(30);
+ }
+ if (salaryInt < 1000) {
+ difficulty += random.nextInt(5);
+ } else if (salaryInt <= 1500) {
+ difficulty += 5 + random.nextInt(15);
+ } else if (salaryInt <= 3000) {
+ difficulty += 20 + random.nextInt(10);
+ } else if (salaryInt <= 4000) {
+ difficulty += 30 + random.nextInt(10);
+ } else if (salaryInt <= 5000) {
+ difficulty += 40 + random.nextInt(20);
+ } else {
+ difficulty += 60 + random.nextInt(20);
+ }
+ if (difficulty > 100) {
+ difficulty = 100;
+ }
+ }
+
+ public int getDifficulty() {
+ return difficulty;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(difficulty);
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/JobDifficultyCompanyList.java b/src/main/java/seedu/address/model/person/JobDifficultyCompanyList.java
new file mode 100644
index 00000000000..166e5d4726f
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/JobDifficultyCompanyList.java
@@ -0,0 +1,127 @@
+package seedu.address.model.person;
+
+import java.util.HashMap;
+
+/**
+ * Represents a list of companies and their corresponding job difficulty.
+ */
+public class JobDifficultyCompanyList {
+ /**
+ * A list of companies and their corresponding job difficulty.
+ */
+ public static final HashMap JOBDIFFCULTYLIST = new HashMap() {
+ {
+ put("google", 70);
+ put("googles", 70);
+ put("facebook", 70);
+ put("amazon", 70);
+ put("apple", 70);
+ put("apples", 70);
+ put("microsoft", 70);
+ put("netflix", 70);
+ put("twitter", 70);
+ put("linkedIn", 70);
+ put("airbnb", 70);
+ put("uber", 70);
+ put("grab", 50);
+ put("shopee", 50);
+ put("lazada", 50);
+ put("carousell", 50);
+ put("tikTok", 60);
+ put("byteDance", 50);
+ put("tencent", 60);
+ put("alibaba", 60);
+ put("baidu", 60);
+ put("jd", 60);
+ put("meituan-dianping", 50);
+ put("didichuxing", 50);
+ put("xiaomi", 50);
+ put("huawei", 50);
+ put("oppo", 50);
+ put("vivo", 50);
+ put("oneplus", 50);
+ put("realme", 50);
+ put("lenovo", 55);
+ put("asus", 55);
+ put("acer", 55);
+ put("dell", 55);
+ put("hp", 55);
+ put("sony", 65);
+ put("samsung", 65);
+ put("lg", 65);
+ put("nokia", 55);
+ put("motorola", 55);
+ put("ibm", 70);
+ put("oracle", 70);
+ put("sap", 70);
+ put("vmware", 70);
+ put("cisco", 70);
+ put("gm", 70);
+ put("accenture", 70);
+ put("tata consultancy services", 70);
+ put("tata", 60);
+ put("wipro", 60);
+ put("sea", 60);
+ put("singtel", 60);
+ put("tiktok", 60);
+ put("pg", 50);
+ put("p & g", 50);
+ put("p&g", 50);
+ put("sp", 50);
+ put("ministry of defence", 50);
+ put("mindef", 60);
+ put("changi airport group", 50);
+ put("cag", 60);
+ put("goto Group", 50);
+ put("goto", 50);
+ put("dbs", 65);
+ put("dbs bank", 65);
+ put("ocbc", 65);
+ put("uob", 65);
+ put("ncs", 55);
+ put("jtc", 55);
+ put("jtc corporation", 55);
+ put("temasek", 70);
+ put("temasek holdings", 70);
+ put("st engineering", 55);
+ put("st", 55);
+ put("gic", 70);
+ put("deloitte", 70);
+ put("bnp paribas", 55);
+ put("dsta", 60);
+ put("smrt", 50);
+ put("micron", 50);
+ put("micron technology", 50);
+ put("phillip", 55);
+ put("phillip securities", 55);
+ put("singhealth", 50);
+ put("jp morgan", 70);
+ put("bank of america", 65);
+ put("cognizant", 60);
+ put("pricewaterhouseCoopers", 70);
+ put("pwc", 70);
+ put("govtech", 60);
+ put("meta", 70);
+ put("cpf", 55);
+ put("imda", 60);
+ put("mas", 65);
+ put("kpmg", 70);
+ put("ey", 65);
+ put("ernst & young", 65);
+ put("tesla", 60);
+ put("razer", 50);
+ put("m1", 50);
+ put("singapore airlines", 55);
+ put("sia", 55);
+ put("synapxe", 55);
+ put("comarch", 55);
+ put("intel", 55);
+ put("intel corporation", 55);
+ put("seagate", 55);
+ }
+ };
+
+ public static HashMap getJobDifficultyCompanyList() {
+ return JOBDIFFCULTYLIST;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/NameOrCompanyNameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameOrCompanyNameContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..08639f3001d
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/NameOrCompanyNameContainsKeywordsPredicate.java
@@ -0,0 +1,45 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Name} or {@code CompanyName} matches any of the keywords given.
+ */
+public class NameOrCompanyNameContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public NameOrCompanyNameContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)
+ || StringUtil.containsWordIgnoreCase(person.getCompanyName().companyName, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof NameOrCompanyNameContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ NameOrCompanyNameContainsKeywordsPredicate otherPredicate = (NameOrCompanyNameContainsKeywordsPredicate) other;
+ return keywords.equals(otherPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index abe8c46b535..d4b55b50d46 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -8,6 +8,7 @@
import java.util.Set;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.tag.Tag;
/**
@@ -17,26 +18,45 @@
public class Person {
// Identity fields
+ private final CompanyName companyName;
private final Name name;
private final Phone phone;
private final Email email;
// Data fields
private final Address address;
+ private final Salary salary;
+ private final Info info;
private final Set tags = new HashSet<>();
-
+ private final InterviewTime dateTime;
+ private final Set programmingLanguages = new HashSet<>();
+ private final Integer priority; // default priority level
+ private final JobDifficulty jobDifficulty;
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
+
+ public Person(
+ CompanyName companyName, Name name, Phone phone, Email email, Address address,
+ InterviewTime dateTime, Salary salary, Info info, Set tags,
+ Set programmingLanguages, Integer priority) {
+ requireAllNonNull(name, phone, email, address, salary, tags);
+ this.companyName = companyName;
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
+ this.dateTime = dateTime;
+ this.salary = salary;
+ this.info = info;
this.tags.addAll(tags);
+ this.programmingLanguages.addAll(programmingLanguages);
+ this.priority = priority;
+ this.jobDifficulty = new JobDifficulty(companyName, salary);
+ }
+ public CompanyName getCompanyName() {
+ return companyName;
}
-
public Name getName() {
return name;
}
@@ -53,6 +73,30 @@ public Address getAddress() {
return address;
}
+ public InterviewTime getDateTime() {
+ return dateTime;
+ }
+ public Salary getSalary() {
+ return salary;
+ }
+ public Info getInfo() {
+ return info;
+ }
+ public Integer getPriority() {
+ return priority;
+ }
+ public JobDifficulty getJobDifficulty() {
+ return jobDifficulty;
+ }
+
+ /**
+ * Returns true if a given string is a valid priority level.
+ */
+ public static boolean isValidPriority(String test) {
+ String validRegex = "^[0-4]$";
+ return test.matches(validRegex);
+ }
+
/**
* Returns an immutable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
@@ -61,6 +105,16 @@ public Set getTags() {
return Collections.unmodifiableSet(tags);
}
+ /**
+ * Returns an immutable set of programming languages.
+ * This set cannot be modified and any attempt to do so will result in an {@code UnsupportedOperationException}.
+ *
+ * @return An immutable set of programming languages.
+ */
+ public Set getProgrammingLanguages() {
+ return Collections.unmodifiableSet(programmingLanguages);
+ }
+
/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
@@ -90,27 +144,35 @@ public boolean equals(Object other) {
}
Person otherPerson = (Person) other;
- return name.equals(otherPerson.name)
+ return companyName.equals(otherPerson.companyName)
+ && name.equals(otherPerson.name)
&& phone.equals(otherPerson.phone)
&& email.equals(otherPerson.email)
&& address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
+ && tags.equals(otherPerson.tags)
+ && programmingLanguages.equals(otherPerson.programmingLanguages);
}
@Override
public int hashCode() {
// use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
+ return Objects.hash(companyName, name, phone, email, address, tags, dateTime, programmingLanguages);
}
@Override
public String toString() {
return new ToStringBuilder(this)
+ .add("company name", companyName)
.add("name", name)
.add("phone", phone)
.add("email", email)
.add("address", address)
+ .add("interview-time", dateTime)
+ .add("salary", salary)
+ .add("info", info)
.add("tags", tags)
+ .add("programming-languages", programmingLanguages)
+ .add("priority", priority)
.toString();
}
diff --git a/src/main/java/seedu/address/model/person/PersonCompanyNameComparator.java b/src/main/java/seedu/address/model/person/PersonCompanyNameComparator.java
new file mode 100644
index 00000000000..fdc76959cce
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonCompanyNameComparator.java
@@ -0,0 +1,20 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their company name.
+ */
+public class PersonCompanyNameComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ // Constructor that accepts a boolean parameter to set the sorting order
+ public PersonCompanyNameComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ int comparisonResult = p1.getCompanyName().companyName.compareTo(p2.getCompanyName().companyName);
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonInterviewTimeComparator.java b/src/main/java/seedu/address/model/person/PersonInterviewTimeComparator.java
new file mode 100644
index 00000000000..f1fe12588e0
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonInterviewTimeComparator.java
@@ -0,0 +1,29 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their interview time.
+ */
+public class PersonInterviewTimeComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ public PersonInterviewTimeComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ if (p1.getDateTime().dateTime == null && p2.getDateTime().dateTime == null) {
+ return 0; // Both dates are null, retain the order
+ } else if (p1.getDateTime().dateTime == null) {
+ return isReverseOrder ? -1 : 1; // p1 has null date, so it should come after p2
+ } else if (p2.getDateTime().dateTime == null) {
+ return isReverseOrder ? 1 : -1; // p2 has null date, so it should come after p1
+ } else {
+ // Compare non-null dates
+ int comparisonResult = p1.getDateTime().dateTime.compareTo(p2.getDateTime().dateTime);
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/person/PersonJobDifficultyComparator.java b/src/main/java/seedu/address/model/person/PersonJobDifficultyComparator.java
new file mode 100644
index 00000000000..f5c0dce2fee
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonJobDifficultyComparator.java
@@ -0,0 +1,20 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their job difficulty.
+ */
+public class PersonJobDifficultyComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ public PersonJobDifficultyComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ int comparisonResult = Double.compare(p1.getJobDifficulty().getDifficulty(),
+ p2.getJobDifficulty().getDifficulty());
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonNameComparator.java b/src/main/java/seedu/address/model/person/PersonNameComparator.java
new file mode 100644
index 00000000000..8dba67ad080
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonNameComparator.java
@@ -0,0 +1,19 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their name.
+ */
+public class PersonNameComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ public PersonNameComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ int comparisonResult = p1.getName().fullName.compareTo(p2.getName().fullName);
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonPriorityComparator.java b/src/main/java/seedu/address/model/person/PersonPriorityComparator.java
new file mode 100644
index 00000000000..20738508b27
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonPriorityComparator.java
@@ -0,0 +1,19 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their priority.
+ */
+public class PersonPriorityComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ public PersonPriorityComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ int comparisonResult = Integer.compare(p1.getPriority(), p2.getPriority());
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonSalaryComparator.java b/src/main/java/seedu/address/model/person/PersonSalaryComparator.java
new file mode 100644
index 00000000000..b100a40c932
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonSalaryComparator.java
@@ -0,0 +1,19 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares two persons based on their salary.
+ */
+public class PersonSalaryComparator implements Comparator {
+ private boolean isReverseOrder = false;
+
+ public PersonSalaryComparator(boolean isReverseOrder) {
+ this.isReverseOrder = isReverseOrder;
+ }
+ @Override
+ public int compare(Person p1, Person p2) {
+ int comparisonResult = Double.compare(p2.getSalary().getSalary1(), p1.getSalary().getSalary1());
+ return isReverseOrder ? -comparisonResult : comparisonResult;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Salary.java b/src/main/java/seedu/address/model/person/Salary.java
new file mode 100644
index 00000000000..494911dd345
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Salary.java
@@ -0,0 +1,133 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+
+/**
+ * Represents a Person's salary in the address book.
+ */
+public class Salary {
+ public static final String MESSAGE_CONSTRAINTS = "Salaries should only contain numbers, with range [0, 2147483647] "
+ + "or two pure digital numbers with '-' in between. "
+ + "There's no space on either side of '-'."
+ + "Both digital numbers should be within the range [0, 2147483647]";
+ public static final String VALIDATION_REGEX = "^(\\d{1,10})(-\\d{1,10})?$";
+ public static final int UPPERBOUND = 2147483647;
+ public static final int LOWERBOUND = 0;
+
+ private int salary1;
+ private int salary2;
+ private boolean isRange;
+
+ /**
+ * Constructs a {@code Salary}.
+ *
+ * @param salary A valid salary.
+ */
+ public Salary(String salary) {
+ requireNonNull(salary);
+ checkArgument(isValidSalary(salary), MESSAGE_CONSTRAINTS);
+ parseSalary(salary);
+ }
+
+ /**
+ * Constructs a {@code Salary}.
+ *
+ * @param salary A valid salary in string format.
+ */
+ public void parseSalary(String salary) {
+ if (salary.contains("-")) {
+ String[] salaryRange = salary.split("-");
+ int salary1 = Integer.parseInt(salaryRange[0]);
+ int salary2 = Integer.parseInt(salaryRange[1]);
+ if (salary1 > salary2) {
+ this.salary1 = salary2;
+ this.salary2 = salary1;
+ } else {
+ this.salary1 = salary1;
+ this.salary2 = salary2;
+ }
+ this.isRange = true;
+ } else {
+ this.salary1 = Integer.parseInt(salary);
+ this.salary2 = Integer.parseInt(salary);
+ this.isRange = false;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid salary format.
+ */
+ public static boolean isValidSalary(String test) {
+ if (!test.matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ if (test.contains("-")) {
+ try {
+ String[] salaryRange = test.split("-");
+ int salary1 = Integer.parseInt(salaryRange[0]);
+ int salary2 = Integer.parseInt(salaryRange[1]);
+ if (salary1 < LOWERBOUND || salary2 < LOWERBOUND) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ } else {
+ try {
+ int salary = Integer.parseInt(test);
+ if (salary < LOWERBOUND) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ @Override
+ public String toString() {
+ if (isRange) {
+ return salary1 + "-" + salary2;
+ } else {
+ return String.valueOf(salary1);
+ }
+ }
+
+ public int getSalary1() {
+ return salary1;
+ }
+
+ public int getSalary2() {
+ return salary2;
+ }
+
+ public boolean isRange() {
+ return isRange;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Salary)) {
+ return false;
+ }
+
+ if (isRange != ((Salary) other).isRange) {
+ return false;
+ }
+
+ if (isRange) {
+ return salary1 == ((Salary) other).salary1 && salary2 == ((Salary) other).salary2;
+ } else {
+ return salary1 == ((Salary) other).salary1;
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/SalaryContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/SalaryContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..1dc70e42bad
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/SalaryContainsKeywordsPredicate.java
@@ -0,0 +1,44 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+
+/**
+ * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ */
+public class SalaryContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public SalaryContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(salaryRange -> salaryRange.isWithinSalaryRange(person.getSalary()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof SalaryContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ SalaryContainsKeywordsPredicate otherSalaryContainsKeywordsPredicate = (SalaryContainsKeywordsPredicate) other;
+ return keywords.equals(otherSalaryContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("salaries", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/SalaryRange.java b/src/main/java/seedu/address/model/person/SalaryRange.java
new file mode 100644
index 00000000000..02a84abb9a8
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/SalaryRange.java
@@ -0,0 +1,148 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+
+/**
+ * Represents a Person's salary in the address book.
+ */
+public class SalaryRange {
+ public static final String MESSAGE_CONSTRAINTS = "SALARY_RANGE should only contain numbers, with range [0, "
+ + "4294967295] "
+ + "or two pure digital numbers with ‘-’ in between or '<=' or '>=' followed by a digital number.\n"
+ + "Numbers can vary from large to small or from small to large.\n"
+ + "Both digital numbers should be within the range [0, 2147483647]\n"
+ + "Examples:\n"
+ + "2000-4000\n"
+ + ">=5000\n"
+ + "<=10000\n";
+ public static final String VALIDATION_REGEX = "^(\\d+-\\d+)|((<=|>=)\\d+)|(\\d+)$";
+ public static final int UPPERBOUND = 2147483647;
+ public static final int LOWERBOUND = 0;
+
+ private int maxSalary;
+ private int minSalary;
+ private boolean isRange;
+ private boolean isMax;
+ private boolean isMin;
+
+ /**
+ * Constructs a {@code Salary}.
+ *
+ * @param salaryRange A valid salary range.
+ */
+ public SalaryRange(String salaryRange) {
+ requireNonNull(salaryRange);
+ checkArgument(isValidSalaryRange(salaryRange), MESSAGE_CONSTRAINTS);
+ parseSalaryRange(salaryRange);
+ }
+
+ /**
+ * Constructs a {@code Salary}.
+ *
+ * @param salaryRange A valid salary in string format.
+ */
+ public void parseSalaryRange(String salaryRange) {
+ if (salaryRange.contains("-")) {
+ String[] range = salaryRange.split("-");
+ int minSalary = Integer.parseInt(range[0]);
+ int maxSalary = Integer.parseInt(range[1]);
+ this.minSalary = Math.min(minSalary, maxSalary);
+ this.maxSalary = Math.max(minSalary, maxSalary);
+ this.isRange = true;
+ } else if (salaryRange.contains(">=")) {
+ String[] range = salaryRange.split(">=");
+ this.minSalary = Integer.parseInt(range[1]);
+ this.maxSalary = UPPERBOUND;
+ this.isMin = true;
+ } else if (salaryRange.contains("<=")) {
+ String[] range = salaryRange.split("<=");
+ this.maxSalary = Integer.parseInt(range[1]);
+ this.minSalary = LOWERBOUND;
+ this.isMax = true;
+ } else {
+ this.minSalary = Integer.parseInt(salaryRange);
+ this.maxSalary = Integer.parseInt(salaryRange);
+ this.isRange = false;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid salary format.
+ */
+ public static boolean isValidSalaryRange(String test) {
+ if (!test.matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ if (test.contains(">=")) {
+ return isValidMin(test);
+ } else if (test.contains("<=")) {
+ return isValidMax(test);
+ } else {
+ return Salary.isValidSalary(test);
+ }
+ }
+ private static boolean isValidMin(String test) {
+ try {
+ String[] salaryRange = test.split(">=");
+ int minSalary = Integer.parseInt(salaryRange[1]);
+ if (minSalary < LOWERBOUND) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+ private static boolean isValidMax(String test) {
+ try {
+ String[] salaryRange = test.split("<=");
+ int maxSalary = Integer.parseInt(salaryRange[1]);
+ if (maxSalary < LOWERBOUND) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the given Salary is within the salary range
+ */
+ public boolean isWithinSalaryRange(Salary salaryToTest) {
+ SalaryRange test = new SalaryRange(salaryToTest.toString());
+ boolean isMinWithinRange = this.minSalary <= test.maxSalary;
+ boolean isMaxWithinRange = this.maxSalary >= test.minSalary;
+ return isMinWithinRange && isMaxWithinRange;
+ }
+
+ @Override
+ public String toString() {
+ if (isRange) {
+ return this.minSalary + "-" + maxSalary;
+ } else if (isMax) {
+ return "<=" + this.maxSalary;
+ } else if (isMin) {
+ return ">=" + this.minSalary;
+ } else {
+ return String.valueOf(minSalary);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ // instanceof handles nulls
+ if (!(other instanceof SalaryRange)) {
+ return false;
+ } else {
+ boolean isMinSame = ((SalaryRange) other).minSalary == this.minSalary;
+ boolean isMaxSame = ((SalaryRange) other).maxSalary == this.maxSalary;
+ return isMinSame && isMaxSame;
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
index cc0a68d79f9..448fc4dbc83 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/seedu/address/model/person/UniquePersonList.java
@@ -3,6 +3,7 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -97,6 +98,15 @@ public void setPersons(List persons) {
internalList.setAll(persons);
}
+ /**
+ * Sorts the list by the given comparator.
+ *
+ * @param comparator The comparator to sort the list by.
+ */
+ public void sortPersonsList(Comparator comparator) {
+ FXCollections.sort(internalList, comparator);
+ }
+
/**
* Returns the backing list as an unmodifiable {@code ObservableList}.
*/
diff --git a/src/main/java/seedu/address/model/person/user/Education.java b/src/main/java/seedu/address/model/person/user/Education.java
new file mode 100644
index 00000000000..a4f2f3ad8e1
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/user/Education.java
@@ -0,0 +1,60 @@
+package seedu.address.model.person.user;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents the user's Education, as part of the Resume
+ */
+public class Education {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+
+ /*
+ * The first character of the address must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String education;
+ /**
+ * Constructs a {@code Education}.
+ *
+ * @param education A valid string.
+ */
+ public Education(String education) {
+ requireNonNull(education);
+ checkArgument(isValidEducation(education), MESSAGE_CONSTRAINTS);
+ this.education = education;
+ }
+ /**
+ * Returns true if a given string is a valid name.
+ */
+ public static boolean isValidEducation(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+ @Override
+ public String toString() {
+ return education;
+ }
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Education)) {
+ return false;
+ }
+
+ Education otherName = (Education) other;
+ return education.equals(otherName.education);
+ }
+
+ @Override
+ public int hashCode() {
+ return education.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/user/User.java b/src/main/java/seedu/address/model/person/user/User.java
new file mode 100644
index 00000000000..de3ce551bf9
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/user/User.java
@@ -0,0 +1,106 @@
+package seedu.address.model.person.user;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import seedu.address.model.language.ProgrammingLanguage;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
+
+/**
+ * Represents the user in the addressbook
+ */
+public class User {
+
+ private static User user;
+ private CompanyName companyName;
+ private Name name;
+ private Phone phone;
+ private Email email;
+
+ // Data fields
+ private Address address;
+ private Salary salary;
+ private Education education;
+ private Set skills = new HashSet<>();
+
+ private User() {
+
+ }
+
+ public static User getInstance() {
+ if (user == null) {
+ // Create a new instance if it doesn't exist
+ user = new User();
+ }
+ return user;
+ }
+
+ public CompanyName getCompanyName() {
+ return companyName;
+ }
+ public void setCompanyName(CompanyName companyName) {
+ this.companyName = companyName;
+ }
+ public Name getName() {
+ return name;
+ }
+ public void setName(Name name) {
+ this.name = name;
+ }
+ public Phone getPhone() {
+ return phone;
+ }
+ public void setPhone(Phone phone) {
+ this.phone = phone;
+ }
+ public Address getAddress() {
+ return address;
+ }
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+ public Salary getSalary() {
+ return salary;
+ }
+ public void setSalary(Salary salary) {
+ this.salary = salary;
+ }
+ public Email getEmail() {
+ return email;
+ }
+ public void setEmail(Email email) {
+ this.email = email;
+ }
+ public Education getEducation() {
+ return education;
+ }
+ public void setEducation(Education education) {
+ this.education = education;
+ }
+ public Set getSkills() {
+ return Collections.unmodifiableSet(skills);
+ }
+ public void setSkills(Set skills) {
+ this.skills.addAll(skills);
+ }
+
+ /**
+ * Resets the values for User singleton class
+ */
+ public void reset() {
+ this.companyName = null;
+ this.name = null;
+ this.phone = null;
+ this.email = null;
+ this.address = null;
+ this.salary = null;
+ this.education = null;
+ this.skills = new HashSet<>();
+ }
+}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
index f1a0d4e233b..9d6c2efb32a 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/address/model/tag/Tag.java
@@ -9,7 +9,8 @@
*/
public class Tag {
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_CONSTRAINTS = "Should be a single alphanumerical word that does"
+ + " not contain spaces.";
public static final String VALIDATION_REGEX = "\\p{Alnum}+";
public final String tagName;
diff --git a/src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..50a95d1c74c
--- /dev/null
+++ b/src/main/java/seedu/address/model/tag/TagContainsKeywordsPredicate.java
@@ -0,0 +1,54 @@
+package seedu.address.model.tag;
+
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import seedu.address.model.person.Person;
+
+/**
+ * Tests that a {@code Person}'s {@code Tag} matches any of the keywords given.
+ */
+public class TagContainsKeywordsPredicate implements Predicate {
+ private final List tags;
+
+ public TagContainsKeywordsPredicate(List tags) {
+ this.tags = tags;
+ }
+
+ public List getTags() {
+ return tags;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ Set personTags = person.getTags();
+ return tags.stream()
+ .anyMatch(personTags::contains);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof TagContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ TagContainsKeywordsPredicate otherTagContainsKeywordsPredicate = (TagContainsKeywordsPredicate) other;
+ return tags.equals(otherTagContainsKeywordsPredicate.tags);
+ }
+
+ @Override
+ public String toString() {
+ List tagNames = tags.stream()
+ .map(Tag::toString)
+ .collect(Collectors.toList());
+
+ return String.join(", ", tagNames);
+ }
+}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..ecf591aafda 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -6,11 +6,16 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
/**
@@ -19,24 +24,31 @@
public class SampleDataUtil {
public static Person[] getSamplePersons() {
return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
+ new Person(new CompanyName("Google"), new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh"
+ + "@example.com"),
new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("friends"), getProgrammingLanguageSet("Java"), 0),
+ new Person(new CompanyName("Google"), new Name("Bernice Yu"), new Phone("99272758"),
+ new Email("berniceyu@example.com"), new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("colleagues", "friends"), getProgrammingLanguageSet("Java"), 1),
+ new Person(new CompanyName("Google"), new Name("Charlotte Oliveiro"), new Phone("93210283"),
+ new Email("charlotte@example.com"), new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("neighbours"), getProgrammingLanguageSet("Java"), 2),
+ new Person(new CompanyName("Google"), new Name("David Li"), new Phone("91031282"),
+ new Email("lidavid@example.com"), new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("family"), getProgrammingLanguageSet("Java"), 3),
+ new Person(new CompanyName("Google"), new Name("Irfan Ibrahim"), new Phone("92492021"),
+ new Email("irfan@example.com"), new Address("Blk 47 Tampines Street 20, #17-35"),
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("classmates"), getProgrammingLanguageSet("Java"), 4),
+ new Person(new CompanyName("Amazon"), new Name("Roy Balakrishnan"), new Phone("92624417"),
+ new Email("royb@example.com"), new Address("Blk 45 Aljunied Street 85, #11-31"),
+ new InterviewTime("121220221400"), new Salary("0"), new Info("Friend of boss"),
+ getTagSet("colleagues"), getProgrammingLanguageSet("Java"), 0),
};
}
@@ -57,4 +69,13 @@ public static Set getTagSet(String... strings) {
.collect(Collectors.toSet());
}
+ /**
+ * Returns a programming language set containing the list of strings given.
+ */
+ public static Set getProgrammingLanguageSet(String... strings) {
+ return Arrays.stream(strings)
+ .map(ProgrammingLanguage::new)
+ .collect(Collectors.toSet());
+ }
+
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index bd1ca0f56c8..33b1e956671 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -10,11 +10,16 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
/**
@@ -23,40 +28,71 @@
class JsonAdaptedPerson {
public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
+ private final String companyName;
private final String name;
private final String phone;
private final String email;
private final String address;
+ private final String dateTime;
+ private final String salary;
+ private final String info;
private final List tags = new ArrayList<>();
+ private final List programmingLanguages = new ArrayList<>();
+ private final String priority;
/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
*/
@JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
+ public JsonAdaptedPerson(@JsonProperty("company name") String companyName, @JsonProperty("name") String name,
+ @JsonProperty("phone") String phone, @JsonProperty("email") String email,
+ @JsonProperty("address") String address, @JsonProperty("dateTime") String dateTime,
+ @JsonProperty("salary") String salary, @JsonProperty("info") String info,
+ @JsonProperty("tags") List tags,
+ @JsonProperty("programmingLanguages") List
+ programmingLanguages,
+ @JsonProperty("priority") String priority) {
+ this.companyName = companyName;
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
+ this.dateTime = dateTime;
+ this.salary = salary;
+ this.info = info;
if (tags != null) {
this.tags.addAll(tags);
}
+ if (programmingLanguages != null) {
+ this.programmingLanguages.addAll(programmingLanguages);
+ }
+ this.priority = priority;
}
/**
* Converts a given {@code Person} into this class for Jackson use.
*/
public JsonAdaptedPerson(Person source) {
+ companyName = source.getCompanyName().companyName;
name = source.getName().fullName;
phone = source.getPhone().value;
email = source.getEmail().value;
address = source.getAddress().value;
+ if (source.getDateTime() == null) {
+ dateTime = null;
+ } else {
+ dateTime = source.getDateTime().rawToString();
+ }
+ salary = source.getSalary().toString();
+ info = source.getInfo().value;
tags.addAll(source.getTags().stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList()));
+ programmingLanguages.addAll(source.getProgrammingLanguages().stream()
+ .map(JsonAdaptedProgrammingLanguage::new)
+ .collect(Collectors.toList()));
+ priority = Integer.toString(source.getPriority());
}
/**
@@ -69,6 +105,18 @@ public Person toModelType() throws IllegalValueException {
for (JsonAdaptedTag tag : tags) {
personTags.add(tag.toModelType());
}
+ final List personProgrammingLanguages = new ArrayList<>();
+ for (JsonAdaptedProgrammingLanguage language : programmingLanguages) {
+ personProgrammingLanguages.add(language.toModelType());
+ }
+ if (companyName == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ CompanyName.class.getSimpleName()));
+ }
+ if (!CompanyName.isValidCompanyName(companyName)) {
+ throw new IllegalValueException(CompanyName.MESSAGE_CONSTRAINTS);
+ }
+ final CompanyName modelCompanyName = new CompanyName(companyName);
if (name == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
@@ -101,9 +149,37 @@ public Person toModelType() throws IllegalValueException {
throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
}
final Address modelAddress = new Address(address);
+ if (!InterviewTime.isValidInterviewTime(dateTime)) {
+ throw new IllegalValueException(InterviewTime.MESSAGE_CONSTRAINTS);
+ }
+ final InterviewTime modelDateTime = new InterviewTime(dateTime);
+
+ if (salary == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Salary.class.getSimpleName()));
+ }
+ if (!Salary.isValidSalary(salary)) {
+ throw new IllegalValueException(Salary.MESSAGE_CONSTRAINTS);
+ }
+
+ final Salary modelSalary = new Salary(salary);
+
+ final Info modelInfo = new Info(info);
final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
+ final Set modelProgrammingLanguages = new HashSet<>(personProgrammingLanguages);
+
+ if (priority == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "Priority"));
+ }
+
+ if (!Person.isValidPriority(priority)) {
+ throw new IllegalValueException("Priority level should be between 1 and 3");
+ }
+
+ final int modelPriority = Integer.parseInt(priority);
+
+ return new Person(modelCompanyName, modelName, modelPhone, modelEmail, modelAddress, modelDateTime,
+ modelSalary, modelInfo, modelTags, modelProgrammingLanguages, modelPriority);
+ }
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedProgrammingLanguage.java b/src/main/java/seedu/address/storage/JsonAdaptedProgrammingLanguage.java
new file mode 100644
index 00000000000..ab0ae28dff4
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedProgrammingLanguage.java
@@ -0,0 +1,50 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.language.ProgrammingLanguage;
+
+/**
+ * Jackson-friendly version of {@link ProgrammingLanguage}.
+ */
+class JsonAdaptedProgrammingLanguage {
+
+ private final String languageName;
+
+ /**
+ * Constructs a {@code JsonAdaptedProgrammingLanguage} with the given {@code languageName}.
+ */
+ @JsonCreator
+ public JsonAdaptedProgrammingLanguage(String languageName) {
+ this.languageName = languageName;
+ }
+
+ /**
+ * Converts a given {@code ProgrammingLanguage} into this class for Jackson use.
+ */
+ public JsonAdaptedProgrammingLanguage(ProgrammingLanguage source) {
+ languageName = source.languageName;
+ }
+
+ @JsonValue
+ public String getLanguageName() {
+ return languageName;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted programming language object into the model's {@code ProgrammingLanguage}
+ * object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted programming language.
+ */
+ public ProgrammingLanguage toModelType() throws IllegalValueException {
+ if (!ProgrammingLanguage.isValidLanguageName(languageName)) {
+ throw new IllegalValueException(ProgrammingLanguage.MESSAGE_CONSTRAINTS);
+ }
+ return new ProgrammingLanguage(languageName);
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
index 5efd834091d..22e58ed46a3 100644
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
@@ -16,7 +16,7 @@
/**
* An Immutable AddressBook that is serializable to JSON format.
*/
-@JsonRootName(value = "addressbook")
+@JsonRootName(value = "ccbot")
class JsonSerializableAddressBook {
public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 3f16b2fcf26..54ea755f4fa 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,7 +15,7 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
+ public static final String USERGUIDE_URL = "https://ay2324s2-cs2103t-t08-3.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..c7901f6da4c 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -34,6 +34,7 @@ public class MainWindow extends UiPart {
private PersonListPanel personListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
+ private ResumeWindow resumeWindow;
@FXML
private StackPane commandBoxPlaceholder;
@@ -66,6 +67,7 @@ public MainWindow(Stage primaryStage, Logic logic) {
setAccelerators();
helpWindow = new HelpWindow();
+ resumeWindow = new ResumeWindow();
}
public Stage getPrimaryStage() {
@@ -160,9 +162,26 @@ private void handleExit() {
(int) primaryStage.getX(), (int) primaryStage.getY());
logic.setGuiSettings(guiSettings);
helpWindow.hide();
+ resumeWindow.hide();
primaryStage.hide();
}
+ /**
+ * Opens the resume window
+ */
+ @FXML
+ public void handleResume() {
+ if (!resumeWindow.isShowing()) {
+ resumeWindow = new ResumeWindow();
+ resumeWindow.show();
+ } else {
+ resumeWindow.close();
+ resumeWindow = new ResumeWindow();
+ resumeWindow.show();
+ resumeWindow.focus();
+ }
+ }
+
public PersonListPanel getPersonListPanel() {
return personListPanel;
}
@@ -182,6 +201,10 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleHelp();
}
+ if (commandResult.isShowResume()) {
+ handleResume();
+ }
+
if (commandResult.isExit()) {
handleExit();
}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 094c42cda82..9b26bd462bc 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -29,6 +29,8 @@ public class PersonCard extends UiPart {
@FXML
private HBox cardPane;
@FXML
+ private Label companyName;
+ @FXML
private Label name;
@FXML
private Label id;
@@ -39,8 +41,19 @@ public class PersonCard extends UiPart {
@FXML
private Label email;
@FXML
+ private Label dateTime;
+ @FXML
+ private Label salary;
+ @FXML
+ private Label info;
+ @FXML
+ private Label jobDifficulty;
+ @FXML
+ private Label programmingLanguagesLabel;
+ @FXML
private FlowPane tags;
-
+ @FXML
+ private FlowPane programmingLanguages;
/**
* Creates a {@code PersonCode} with the given {@code Person} and index to display.
*/
@@ -48,12 +61,45 @@ public PersonCard(Person person, int displayedIndex) {
super(FXML);
this.person = person;
id.setText(displayedIndex + ". ");
+ companyName.setText(person.getCompanyName().companyName);
name.setText(person.getName().fullName);
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
email.setText(person.getEmail().value);
+ dateTime.setText("Interview Time: " + person.getDateTime().toString());
+ salary.setText("Salary: " + person.getSalary().toString() + "$");
+ info.setText(person.getInfo().value);
+ jobDifficulty.setText("Predict Job Difficulty: " + person.getJobDifficulty().toString() + "%");
person.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
.forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ person.getProgrammingLanguages().stream()
+ .sorted(Comparator.comparing(pl -> pl.languageName))
+ .forEach(pl -> programmingLanguages.getChildren().add(
+ new Label("[" + pl.languageName + "] ")));
+ updateCardColor(person);
+ }
+ private void updateCardColor(Person person) {
+ String styleClass;
+ switch (person.getPriority()) {
+ case 0:
+ styleClass = "priorityHigh";
+ break;
+ case 1:
+ styleClass = "priorityMedium";
+ break;
+ case 2:
+ styleClass = "priorityLow";
+ break;
+ case 3:
+ styleClass = "priorityLower";
+ break;
+ case 4:
+ styleClass = "priorityLowest";
+ break;
+ default:
+ styleClass = "priorityDefault";
+ }
+ cardPane.getStyleClass().add(styleClass);
}
}
diff --git a/src/main/java/seedu/address/ui/ResumeWindow.java b/src/main/java/seedu/address/ui/ResumeWindow.java
new file mode 100644
index 00000000000..2a65beee294
--- /dev/null
+++ b/src/main/java/seedu/address/ui/ResumeWindow.java
@@ -0,0 +1,174 @@
+package seedu.address.ui;
+
+import java.util.Comparator;
+import java.util.logging.Logger;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.ClipboardContent;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.person.user.User;
+
+/**
+ * Controller for resume page
+ */
+public class ResumeWindow extends UiPart {
+ private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
+ private static final String FXML = "ResumeWindow2.fxml";
+ private User user = User.getInstance();
+
+ @FXML
+ private Label companyName;
+ @FXML
+ private Label name;
+ @FXML
+ private Label phone;
+ @FXML
+ private Label address;
+ @FXML
+ private Label email;
+ @FXML
+ private Label salary;
+ @FXML
+ private Label resume;
+ @FXML
+ private Label education;
+ @FXML
+ private Label skills;
+ @FXML
+ private VBox skillsVbox;
+ @FXML
+ private Label contactLabel;
+ @FXML
+ private VBox contactBox;
+ @FXML
+ private Button copyButton;
+
+ private Stage currentStage;
+
+ /**
+ * Creates a new ResumeWindow.
+ *
+ * @param root Stage to use as the root of the ResumeWindow.
+ */
+ public ResumeWindow(Stage root) {
+ super(FXML, root);
+ if (user.getName() != null) {
+ resume.setText("Resume added");
+ companyName.setText("Previous employment: " + user.getCompanyName().companyName);
+ companyName.setVisible(true);
+ name.setText("Name: " + user.getName().fullName);
+ name.setVisible(true);
+ phone.setText("Phone: " + user.getPhone().value);
+ phone.setVisible(true);
+ address.setText("Place of residence: " + user.getAddress().value);
+ address.setVisible(true);
+ email.setText("Email: " + user.getEmail().value);
+ email.setVisible(true);
+ salary.setText("Previous salary: " + "$" + user.getSalary().toString());
+ salary.setVisible(true);
+ education.setText("Highest Education: " + user.getEducation());
+ education.setVisible(true);
+ skills.setVisible(true);
+ skillsVbox.setVisible(true);
+
+ //for contact info box
+ contactLabel.setVisible(true);
+ contactBox.setVisible(true);
+
+ user.getSkills().stream()
+ .sorted(Comparator.comparing(pl -> pl.languageName))
+ .forEach(pl -> skillsVbox.getChildren().add(
+ new Label(pl.languageName)));
+ } else {
+ resume.setText("No resume added");
+ }
+ }
+
+ /**
+ * Creates a new ResumeWindow.
+ */
+ public ResumeWindow() {
+ this(new Stage());
+ }
+
+ /**
+ * Shows the help window.
+ * @throws IllegalStateException
+ *
+ *
+ * if this method is called on a thread other than the JavaFX Application Thread.
+ *
+ *
+ * if this method is called during animation or layout processing.
+ *
+ *
+ * if this method is called on the primary stage.
+ *
+ *
+ * if {@code dialogStage} is already showing.
+ *
+ *
+ */
+ public void show() {
+ logger.fine("Showing user's resume.");
+ getRoot().show();
+ getRoot().centerOnScreen();
+ }
+
+ public void close() {
+ getRoot().close();
+ }
+
+ /**
+ * Allow user to generate resume as string to copy
+ * @return
+ */
+ public String generateResume() {
+ StringBuilder resumeBuilder = new StringBuilder();
+ resumeBuilder.append(companyName.getText()).append("\n");
+ resumeBuilder.append(name.getText()).append("\n");
+ resumeBuilder.append(phone.getText()).append("\n");
+ resumeBuilder.append(email.getText()).append("\n");
+ resumeBuilder.append(address.getText()).append("\n");
+ resumeBuilder.append(salary.getText()).append("\n");
+ resumeBuilder.append("Skills: ").append("\n");
+ skillsVbox.getChildren().forEach(label -> resumeBuilder.append("- ").append(((Label) label).getText())
+ .append("\n"));
+
+ return resumeBuilder.toString();
+ }
+
+ /**
+ * Returns true if the help window is currently being shown.
+ */
+ public boolean isShowing() {
+ return getRoot().isShowing();
+ }
+
+ /**
+ * Hides the help window.
+ */
+ public void hide() {
+ getRoot().hide();
+ }
+
+ /**
+ * Focuses on the help window.
+ */
+ public void focus() {
+ getRoot().requestFocus();
+ }
+
+ @FXML
+ private void copyResume() {
+ final Clipboard clipboard = Clipboard.getSystemClipboard();
+ final ClipboardContent resume = new ClipboardContent();
+ resume.putString(generateResume());
+ clipboard.setContent(resume);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java
index fdf024138bc..0565bccbf2d 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/seedu/address/ui/UiManager.java
@@ -20,7 +20,7 @@ public class UiManager implements Ui {
public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane";
private static final Logger logger = LogsCenter.getLogger(UiManager.class);
- private static final String ICON_APPLICATION = "/images/address_book_32.png";
+ private static final String ICON_APPLICATION = "/images/ccbot_logo_1.png";
private Logic logic;
private MainWindow mainWindow;
diff --git a/src/main/resources/images/ccbot_logo.png b/src/main/resources/images/ccbot_logo.png
new file mode 100644
index 00000000000..60e90c5bfb2
Binary files /dev/null and b/src/main/resources/images/ccbot_logo.png differ
diff --git a/src/main/resources/images/ccbot_logo_1.png b/src/main/resources/images/ccbot_logo_1.png
new file mode 100644
index 00000000000..d33b6d1927a
Binary files /dev/null and b/src/main/resources/images/ccbot_logo_1.png differ
diff --git a/src/main/resources/images/resume_bg.jpg b/src/main/resources/images/resume_bg.jpg
new file mode 100644
index 00000000000..3c79ff4b7f7
Binary files /dev/null and b/src/main/resources/images/resume_bg.jpg differ
diff --git a/src/main/resources/view/CustomTheme.css b/src/main/resources/view/CustomTheme.css
new file mode 100644
index 00000000000..77247e52a8e
--- /dev/null
+++ b/src/main/resources/view/CustomTheme.css
@@ -0,0 +1,376 @@
+.background {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ background-color: #8B8B00; /* Used in the default.html file */
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #555555;
+ -fx-opacity: 0.9;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 32pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.text-field {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+}
+
+.tab-pane {
+ -fx-padding: 0 0 0 1;
+}
+
+.tab-pane .tab-header-area {
+ -fx-padding: 0 0 0 0;
+ -fx-min-height: 0;
+ -fx-max-height: 0;
+}
+
+.table-view {
+ -fx-base: #1d1d1d;
+ -fx-control-inner-background: #1d1d1d;
+ -fx-background-color: #1d1d1d;
+ -fx-table-cell-border-color: transparent;
+ -fx-table-header-border-color: transparent;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal .split-pane-divider {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: transparent transparent transparent #4d4d4d;
+}
+
+.split-pane {
+ -fx-border-radius: 1;
+ -fx-border-width: 1;
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.list-view {
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.list-cell {
+ -fx-label-padding: 0 0 0 0;
+ -fx-graphic-text-gap : 0;
+ -fx-padding: 0 0 0 0;
+}
+
+.list-cell:filled:even {
+ -fx-background-color: #54707f;
+}
+
+.list-cell:filled:odd {
+ -fx-background-color: #4c6d7b;
+}
+
+.list-cell:filled:selected {
+ -fx-background-color: #2f3e54;
+}
+
+.list-cell:filled:selected #cardPane {
+ -fx-border-color: #040404;
+ -fx-border-width: 1;
+}
+
+.list-cell .label {
+ -fx-text-fill: rgb(255, 255, 255);
+}
+
+.cell_big_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #010504;
+}
+
+.cell_small_label {
+ -fx-font-family: "Segoe UI";
+ -fx-font-size: 13px;
+ -fx-text-fill: #010504;
+}
+
+.stack-pane {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.pane-with-border {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: derive(#1d1d1d, 10%);
+ -fx-border-top-width: 1px;
+}
+
+.status-bar {
+ -fx-background-color: derive(#1d1d1d, 30%);
+}
+
+.result-display {
+ -fx-background-color: transparent;
+ -fx-font-family: "DejaVu Sans Mono";
+ -fx-font-size: 13pt;
+ -fx-text-fill: rgb(188, 188, 188);
+}
+
+.result-display .label {
+ -fx-text-fill: rgb(0, 0, 0) !important;
+}
+
+.status-bar .label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
+}
+
+.status-bar-with-border {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 25%);
+ -fx-border-width: 1px;
+}
+
+.status-bar-with-border .label {
+ -fx-text-fill: white;
+}
+
+.grid-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 30%);
+ -fx-border-width: 1px;
+}
+
+.grid-pane .stack-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+}
+
+.context-menu {
+ -fx-background-color: derive(#1d1d1d, 50%);
+}
+
+.context-menu .label {
+ -fx-text-fill: white;
+}
+
+.menu-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.menu-bar .label {
+ -fx-font-size: 14pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 0.9;
+}
+
+.menu .left-container {
+ -fx-background-color: black;
+}
+
+/*
+ * Metro style Push Button
+ * Author: Pedro Duque Vieira
+ * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
+ */
+.button {
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: #e2e2e2;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-color: #1d1d1d;
+ -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+ -fx-font-size: 11pt;
+ -fx-text-fill: #d8d8d8;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+ -fx-background-color: #3a3a3a;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+ -fx-border-color: white, white;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid, segments(1, 1);
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #1d1d1d;
+ -fx-text-fill: white;
+}
+
+.button:default {
+ -fx-background-color: -fx-focus-color;
+ -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+ -fx-background-color: derive(-fx-focus-color, 30%);
+}
+
+.dialog-pane {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.button-bar > *.container {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.label.content {
+ -fx-font-size: 14px;
+ -fx-font-weight: bold;
+ -fx-text-fill: white;
+}
+
+.dialog-pane:header *.header-panel {
+ -fx-background-color: derive(#1d1d1d, 25%);
+}
+
+.dialog-pane:header *.header-panel *.label {
+ -fx-font-size: 18px;
+ -fx-font-style: italic;
+ -fx-fill: white;
+ -fx-text-fill: white;
+}
+
+.scroll-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.scroll-bar .thumb {
+ -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-background-insets: 3;
+}
+
+.scroll-bar .increment-button, .scroll-bar .decrement-button {
+ -fx-background-color: transparent;
+ -fx-padding: 0 0 0 0;
+}
+
+.scroll-bar .increment-arrow, .scroll-bar .decrement-arrow {
+ -fx-shape: " ";
+}
+
+.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .decrement-arrow {
+ -fx-padding: 1 8 1 8;
+}
+
+.scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow {
+ -fx-padding: 8 1 8 1;
+}
+
+#cardPane {
+ -fx-background-color: transparent;
+ -fx-border-width: 0;
+}
+
+#commandTypeLabel {
+ -fx-font-size: 11px;
+ -fx-text-fill: #F70D1A;
+}
+
+#commandTextField {
+ -fx-background-color: transparent #383838 transparent #383838;
+ -fx-background-insets: 0;
+ -fx-border-color: #383838 #383838 #ffffff #383838;
+ -fx-border-insets: 0;
+ -fx-border-width: 1;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 13pt;
+ -fx-text-fill: white;
+}
+
+#filterField, #personListPanel, #personWebpage {
+ -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
+}
+
+#resultDisplay .content {
+ -fx-background-color: transparent, #383838, transparent, #383838;
+ -fx-background-radius: 0;
+}
+
+#tags {
+ -fx-hgap: 7;
+ -fx-vgap: 3;
+}
+
+#tags .label {
+ -fx-text-fill: white;
+ -fx-background-color: #20b038;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 11;
+}
+
+#cardPane.priorityHigh {
+ -fx-background-color: #E11F1F;
+}
+
+#cardPane.priorityMedium {
+ -fx-background-color: #E18D1F;
+}
+
+#cardPane.priorityLow {
+ -fx-background-color: #159584;
+}
+
+#cardPane.priorityLower {
+ -fx-background-color: #1550C5;
+}
+
+#cardPane.priorityLowest {
+ -fx-background-color: #8A15C5;
+}
+
+#cardPane.priorityDefault {
+ -fx-background-color: grey;
+}
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..45e414a6328 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -149,8 +149,8 @@
.result-display {
-fx-background-color: transparent;
-fx-font-family: "Segoe UI Light";
- -fx-font-size: 13pt;
- -fx-text-fill: white;
+ -fx-font-size: 20pt;
+ -fx-text-fill: rgb(81, 255, 0);
}
.result-display .label {
@@ -350,3 +350,19 @@
-fx-background-radius: 2;
-fx-font-size: 11;
}
+
+.personListCard.priorityHigh {
+ -fx-background-color: red;
+}
+
+.personListCard.priorityMedium {
+ -fx-background-color: yellow;
+}
+
+.personListCard.priorityLow {
+ -fx-background-color: green;
+}
+
+.personListCard.priorityDefault {
+ -fx-background-color: grey;
+}
diff --git a/src/main/resources/view/Extensions.css b/src/main/resources/view/Extensions.css
index bfe82a85964..5fafef71f8f 100644
--- a/src/main/resources/view/Extensions.css
+++ b/src/main/resources/view/Extensions.css
@@ -1,6 +1,6 @@
.error {
- -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */
+ -fx-text-fill: #e14620 !important; /* The error class should always override the default text-fill style */
}
.list-cell:empty {
@@ -10,11 +10,37 @@
.tag-selector {
-fx-border-width: 1;
- -fx-border-color: white;
+ -fx-border-color: rgb(255, 255, 255);
-fx-border-radius: 3;
-fx-background-radius: 3;
}
.tooltip-text {
- -fx-text-fill: white;
+ -fx-text-fill: rgb(255, 255, 255);
}
+
+.personListCard.priorityHigh {
+ -fx-background-color: red;
+}
+
+.personListCard.priorityMedium {
+ -fx-background-color: yellow;
+}
+
+.personListCard.priorityLow {
+ -fx-background-color: green;
+}
+
+.personListCard.priorityLower {
+ -fx-background-color: yellow;
+}
+
+.personListCard.priorityLowest {
+ -fx-background-color: gold;
+}
+
+.personListCard.priorityDefault {
+ -fx-background-color: grey;
+}
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..e1ac0b9f0de 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -6,51 +6,54 @@
-
+
-
+
-
+
-
+
+
-
-
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index f5e812e25e6..1b650661748 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -7,30 +7,45 @@
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml
index 01b691792a9..c6c34bb6504 100644
--- a/src/main/resources/view/ResultDisplay.fxml
+++ b/src/main/resources/view/ResultDisplay.fxml
@@ -3,7 +3,6 @@
-
-
+
+
diff --git a/src/main/resources/view/ResumeWindow.fxml b/src/main/resources/view/ResumeWindow.fxml
new file mode 100644
index 00000000000..5fdc3a6fe70
--- /dev/null
+++ b/src/main/resources/view/ResumeWindow.fxml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/ResumeWindow2.fxml b/src/main/resources/view/ResumeWindow2.fxml
new file mode 100644
index 00000000000..0d39866a2c6
--- /dev/null
+++ b/src/main/resources/view/ResumeWindow2.fxml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
index 6a4d2b7181c..8a9c0b1544e 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
@@ -1,10 +1,12 @@
{
"persons": [ {
+ "companyName": "Valid Company Name",
"name": "Valid Person",
"phone": "9482424",
"email": "hans@example.com",
"address": "4th street"
}, {
+ "companyName": "Valid Company Name",
"name": "Person With Invalid Phone Field",
"phone": "948asdf2424",
"email": "hans@example.com",
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
index ccd21f7d1a9..124cffc2b71 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
@@ -1,5 +1,6 @@
{
"persons": [ {
+ "company name": "Valid Company Name",
"name": "Person with invalid name field: Ha!ns Mu@ster",
"phone": "9482424",
"email": "hans@example.com",
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
index a7427fe7aa2..ad6300f9cfa 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
@@ -1,14 +1,27 @@
{
"persons": [ {
+ "companyName": "Google",
"name": "Alice Pauline",
"phone": "94351253",
"email": "alice@example.com",
"address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
+ "dateTime": "121220221400",
+ "salary" : "0",
+ "info" : "Friend of boss",
+ "tags": [ "friends" ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "3"
}, {
+ "companyName": "Google",
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "dateTime": "121220221400",
+ "salary" : "0",
+ "info" : "Friend of boss",
+ "tags": [ "friends" ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "3"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
index ad3f135ae42..5a7a5fa4a3c 100644
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
@@ -1,8 +1,10 @@
{
"persons": [ {
+ "companyName": "Google",
"name": "Hans Muster",
"phone": "9482424",
"email": "invalid@email!3e",
- "address": "4th street"
+ "address": "4th street",
+ "datetime": "121320221400"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
index 72262099d35..f070f8fad74 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
@@ -1,46 +1,88 @@
{
"_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
"persons" : [ {
+ "companyName" : "Google",
"name" : "Alice Pauline",
"phone" : "94351253",
"email" : "alice@example.com",
"address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ "friends" ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "2"
}, {
+ "companyName": "Amazon",
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
"address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ "owesMoney", "friends" ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "2"
}, {
+ "companyName" : "Shopee",
"name" : "Carl Kurz",
"phone" : "95352563",
"email" : "heinz@example.com",
"address" : "wall street",
- "tags" : [ ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "2"
}, {
+ "companyName" : "Tiktok",
"name" : "Daniel Meier",
"phone" : "87652533",
"email" : "cornelia@example.com",
"address" : "10th street",
- "tags" : [ "friends" ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ "friends" ],
+ "programmingLanguages": [ "Java" ],
+ "priority" : "2"
}, {
+ "companyName" : "Shopback",
"name" : "Elle Meyer",
"phone" : "9482224",
"email" : "werner@example.com",
"address" : "michegan ave",
- "tags" : [ ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ ],
+ "programmingLanguages": [ ],
+ "priority" : "2"
}, {
+ "companyName" : "Apple",
"name" : "Fiona Kunz",
"phone" : "9482427",
"email" : "lydia@example.com",
"address" : "little tokyo",
- "tags" : [ ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ ],
+ "programmingLanguages": [ ],
+ "priority" : "2"
}, {
+ "companyName" : "Microsoft",
"name" : "George Best",
"phone" : "9482442",
"email" : "anna@example.com",
"address" : "4th street",
- "tags" : [ ]
+ "dateTime" : "121220221400",
+ "salary" : "0",
+ "info" : "Nil",
+ "tags" : [ ],
+ "programmingLanguages": [ ],
+ "priority" : "2"
} ]
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
index 1037548a9cd..26141cbb0c8 100644
--- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
@@ -9,5 +9,5 @@
"z" : 99
}
},
- "addressBookFilePath" : "addressbook.json"
+ "addressBookFilePath" : "ccbot.json"
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
index b819bed900a..65d9efefe7b 100644
--- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
@@ -7,5 +7,5 @@
"y" : 100
}
},
- "addressBookFilePath" : "addressbook.json"
+ "addressBookFilePath" : "ccbot.json"
}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index baf8ce336a2..8c94bcc984b 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -4,9 +4,12 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.COMPANY_NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.INTERVIEWTIME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.PROGRAMMING_LANG_DESC_DEFAULT;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.AMY;
@@ -46,7 +49,7 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ new JsonAddressBookStorage(temporaryFolder.resolve("ccbot.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
@@ -165,10 +168,11 @@ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
logic = new LogicManager(model, storage);
// Triggers the saveAddressBook method by executing an add command
- String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY;
+ String addCommand = AddCommand.COMMAND_WORD + COMPANY_NAME_DESC_AMY + NAME_DESC_AMY + PHONE_DESC_AMY
+ + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + INTERVIEWTIME_DESC_AMY + PROGRAMMING_LANG_DESC_DEFAULT;
Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- ModelManager expectedModel = new ModelManager();
+ ModelManager expectedModel =
+ new ModelManager();
expectedModel.addPerson(expectedPerson);
assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index 90e8253f48e..e4622e51fd0 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -10,6 +10,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
@@ -157,6 +158,10 @@ public ObservableList getFilteredPersonList() {
public void updateFilteredPersonList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void updateSortedPersonList(Comparator comparator) {
+ throw new AssertionError("This method should not be called.");
+ }
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/AddResumeCommandTest.java b/src/test/java/seedu/address/logic/commands/AddResumeCommandTest.java
new file mode 100644
index 00000000000..5b0eaa4514b
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/AddResumeCommandTest.java
@@ -0,0 +1,22 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.person.user.User;
+
+public class AddResumeCommandTest {
+ //Create user for testing
+ private User user = User.getInstance();
+ @Test
+ public void constructor_nullUser_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new AddResumeCommand(null));
+ }
+ @Test
+ public void execution_nullModel_throwsNullPointerException() throws Exception {
+ AddResumeCommand addResumeCommand = new AddResumeCommand(user);
+ assertThrows(NullPointerException.class, () -> addResumeCommand.execute(null));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
index 7b8c7cd4546..bb6848c7f6f 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
@@ -14,7 +14,7 @@ public void equals() {
// same values -> returns true
assertTrue(commandResult.equals(new CommandResult("feedback")));
- assertTrue(commandResult.equals(new CommandResult("feedback", false, false)));
+ assertTrue(commandResult.equals(new CommandResult("feedback", false, false, false)));
// same object -> returns true
assertTrue(commandResult.equals(commandResult));
@@ -29,10 +29,10 @@ public void equals() {
assertFalse(commandResult.equals(new CommandResult("different")));
// different showHelp value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", true, false)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", true, false, false)));
// different exit value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", false, true)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", false, false, true)));
}
@Test
@@ -46,10 +46,10 @@ public void hashcode() {
assertNotEquals(commandResult.hashCode(), new CommandResult("different").hashCode());
// different showHelp value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false, false).hashCode());
// different exit value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, false, true).hashCode());
}
@Test
@@ -57,6 +57,7 @@ public void toStringMethod() {
CommandResult commandResult = new CommandResult("feedback");
String expected = CommandResult.class.getCanonicalName() + "{feedbackToUser="
+ commandResult.getFeedbackToUser() + ", showHelp=" + commandResult.isShowHelp()
+ + ", showResume=" + commandResult.isShowResume()
+ ", exit=" + commandResult.isExit() + "}";
assertEquals(expected, commandResult.toString());
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..ed534324018 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,9 +3,15 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.testutil.Assert.assertThrows;
@@ -25,7 +31,8 @@
* Contains helper methods for testing commands.
*/
public class CommandTestUtil {
-
+ public static final String VALID_COMPANY_NAME_AMY = "Amazon";
+ public static final String VALID_COMPANY_NAME_BOB = "Google";
public static final String VALID_NAME_AMY = "Amy Bee";
public static final String VALID_NAME_BOB = "Bob Choo";
public static final String VALID_PHONE_AMY = "11111111";
@@ -34,9 +41,23 @@ public class CommandTestUtil {
public static final String VALID_EMAIL_BOB = "bob@example.com";
public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
+ public static final String VALID_INTERVIEWTIME_AMY = "121220221400";
+ public static final String VALID_INTERVIEWTIME_BOB = "111220221400";
+ public static final String VALID_SALARY_AMY = "100";
+ public static final String VALID_SALARY_BOB = "50";
+ public static final String VALID_INFO_AMY = "Uni Friend";
+ public static final String VALID_INFO_BOB = "Cousin";
public static final String VALID_TAG_HUSBAND = "husband";
public static final String VALID_TAG_FRIEND = "friend";
-
+ public static final String VALID_PROGRAMMING_LANG_JAVA = "Java";
+ public static final String VALID_PRIORITY_AMY = "2";
+ public static final String VALID_PRIORITY_BOB = "2";
+ public static final String VALID_SALARY_RANGE_MAX = "<4000";
+ public static final String VALID_SALARY_RANGE_MIN = ">5000";
+ public static final String VALID_SALARY_RANGE = "1000-3000";
+
+ public static final String COMPANY_NAME_DESC_AMY = " " + PREFIX_COMPANY_NAME + VALID_COMPANY_NAME_AMY;
+ public static final String COMPANY_NAME_DESC_BOB = " " + PREFIX_COMPANY_NAME + VALID_COMPANY_NAME_BOB;
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY;
@@ -45,14 +66,30 @@ public class CommandTestUtil {
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
+ public static final String INTERVIEWTIME_DESC_AMY = " " + PREFIX_INTERVIEWTIME + VALID_INTERVIEWTIME_AMY;
+ public static final String INTERVIEWTIME_DESC_BOB = " " + PREFIX_INTERVIEWTIME + VALID_INTERVIEWTIME_BOB;
+ public static final String SALARY_DESC_AMY = " " + PREFIX_SALARY + VALID_SALARY_AMY;
+ public static final String SALARY_DESC_BOB = " " + PREFIX_SALARY + VALID_SALARY_BOB;
+ public static final String INFO_DESC_AMY = " " + PREFIX_INFO + VALID_INFO_AMY;
+ public static final String INFO_DESC_BOB = " " + PREFIX_INFO + VALID_INFO_BOB;
public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
-
+ public static final String PROGRAMMING_LANG_DESC_DEFAULT =
+ " " + PREFIX_PROGRAMMING_LANGUAGE + VALID_PROGRAMMING_LANG_JAVA;
+ public static final String PRIORITY_DESC_AMY = " " + PREFIX_PRIORITY + VALID_PRIORITY_AMY;
+ public static final String PRIORITY_DESC_BOB = " " + PREFIX_PRIORITY + VALID_PRIORITY_BOB;
+ public static final String INVALID_COMPANY_NAME_DESC = " " + PREFIX_COMPANY_NAME
+ + "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1";
+ // length of company name is <= 100
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
+ public static final String INVALID_INTERVIEWTIME_DESC = " " + PREFIX_INTERVIEWTIME
+ + "121320221400"; //wrong format
+ public static final String INVALID_SALARY_DESC = " " + PREFIX_SALARY + "0$"; // '$' not allowed in salary
public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_PRIORITY_DESC = " " + PREFIX_PRIORITY + "5"; // priority should be 0-4
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
@@ -61,12 +98,27 @@ public class CommandTestUtil {
public static final EditCommand.EditPersonDescriptor DESC_BOB;
static {
- DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_FRIEND).build();
- DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ DESC_AMY = new EditPersonDescriptorBuilder()
+ .withCompanyName(VALID_COMPANY_NAME_AMY)
+ .withName(VALID_NAME_AMY)
+ .withPhone(VALID_PHONE_AMY)
+ .withEmail(VALID_EMAIL_AMY)
+ .withAddress(VALID_ADDRESS_AMY)
+ .withInterviewTime(VALID_INTERVIEWTIME_AMY)
+ .withSalary(VALID_SALARY_AMY)
+ .withInfo(VALID_INFO_AMY)
+ .withTags(VALID_TAG_FRIEND)
+ .withPriority(VALID_PRIORITY_AMY).build();
+ DESC_BOB = new EditPersonDescriptorBuilder()
+ .withCompanyName(VALID_COMPANY_NAME_BOB)
+ .withName(VALID_NAME_BOB)
+ .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
+ .withAddress(VALID_ADDRESS_BOB)
+ .withInterviewTime(VALID_INTERVIEWTIME_BOB)
+ .withSalary(VALID_SALARY_BOB)
+ .withInfo(VALID_INFO_BOB)
+ .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
+ .withPriority(VALID_PRIORITY_BOB).build();
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 469dd97daa7..63580204537 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -60,6 +60,7 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
.withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
+
EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
index b17c1f3d5c2..51a0be3e3bf 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
@@ -60,12 +60,18 @@ public void equals() {
@Test
public void toStringMethod() {
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- String expected = EditPersonDescriptor.class.getCanonicalName() + "{name="
+ String expected = EditPersonDescriptor.class.getCanonicalName() + "{company name="
+ + editPersonDescriptor.getCompanyName().orElse(null) + ", name="
+ editPersonDescriptor.getName().orElse(null) + ", phone="
+ editPersonDescriptor.getPhone().orElse(null) + ", email="
+ editPersonDescriptor.getEmail().orElse(null) + ", address="
- + editPersonDescriptor.getAddress().orElse(null) + ", tags="
- + editPersonDescriptor.getTags().orElse(null) + "}";
+ + editPersonDescriptor.getAddress().orElse(null) + ", dateTime="
+ + editPersonDescriptor.getDateTime().orElse(null) + ", salary="
+ + editPersonDescriptor.getInfo().orElse(null) + ", info="
+ + editPersonDescriptor.getSalary().orElse(null) + ", tags="
+ + editPersonDescriptor.getTags().orElse(null) + ", programmingLanguages="
+ + editPersonDescriptor.getProgrammingLanguages().orElse(null) + ", priority="
+ + editPersonDescriptor.getPriority().orElse(null) + "}";
assertEquals(expected, editPersonDescriptor.toString());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
index 9533c473875..f5854e5dfa3 100644
--- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
@@ -14,7 +14,7 @@ public class ExitCommandTest {
@Test
public void execute_exit_success() {
- CommandResult expectedCommandResult = new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ CommandResult expectedCommandResult = new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, false, true);
assertCommandSuccess(new ExitCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FilterInterviewTimeCommandTest.java b/src/test/java/seedu/address/logic/commands/FilterInterviewTimeCommandTest.java
new file mode 100644
index 00000000000..218fd645247
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FilterInterviewTimeCommandTest.java
@@ -0,0 +1,107 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.CARL;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
+import static seedu.address.testutil.TypicalPersons.ELLE;
+import static seedu.address.testutil.TypicalPersons.FIONA;
+import static seedu.address.testutil.TypicalPersons.GEORGE;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.InterviewTime;
+import seedu.address.model.person.InterviewTimeContainsKeywordsPredicate;
+
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FilterInterviewCommand}.
+ */
+public class FilterInterviewTimeCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ InterviewTimeContainsKeywordsPredicate firstPredicate =
+ new InterviewTimeContainsKeywordsPredicate(Collections.singletonList(
+ Arrays.asList(
+ new InterviewTime("121220210000"), null)
+ ));
+ InterviewTimeContainsKeywordsPredicate secondPredicate =
+ new InterviewTimeContainsKeywordsPredicate(Collections.singletonList(Arrays.asList(
+ new InterviewTime("121220220000"), new InterviewTime("121220250000"))
+ ));
+
+ FilterInterviewTimeCommand filterInterviewTimeFirstCommand = new FilterInterviewTimeCommand(firstPredicate);
+ FilterInterviewTimeCommand filterInterviewTimeSecondCommand = new FilterInterviewTimeCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(filterInterviewTimeFirstCommand.equals(filterInterviewTimeFirstCommand));
+
+ // same values -> returns true
+ FilterInterviewTimeCommand findInterviewTimeFirstCommandCopy = new FilterInterviewTimeCommand(firstPredicate);
+ assertTrue(filterInterviewTimeFirstCommand.equals(findInterviewTimeFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(filterInterviewTimeFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(filterInterviewTimeFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(filterInterviewTimeFirstCommand.equals(filterInterviewTimeSecondCommand));
+ }
+
+ @Test
+ public void execute_oneInterviewTime_multiplePersonsFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1);
+ InterviewTimeContainsKeywordsPredicate predicate = new InterviewTimeContainsKeywordsPredicate(
+ Collections.singletonList(Arrays.asList(
+ new InterviewTime("121220221430"), new InterviewTime("121220222359")
+ ))
+ );
+ FilterInterviewTimeCommand command = new FilterInterviewTimeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(BENSON), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_multipleInterviewTimes_multiplePersonsFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 7);
+ InterviewTimeContainsKeywordsPredicate predicate = new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220221430")),
+ Arrays.asList(new InterviewTime("121220221430"), null)
+ ));
+ FilterInterviewTimeCommand command = new FilterInterviewTimeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE), model.getFilteredPersonList());
+ }
+
+
+ @Test
+ public void toStringMethod() {
+ InterviewTimeContainsKeywordsPredicate predicate =
+ new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220221430")),
+ Arrays.asList(new InterviewTime("121220221430"), null)
+ ));
+ FilterInterviewTimeCommand filterInterviewTimeCommand = new FilterInterviewTimeCommand(predicate);
+ String expected = FilterInterviewTimeCommand.class.getCanonicalName() + "{interviewTime=" + predicate + "}";
+ assertEquals(expected, filterInterviewTimeCommand.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FilterProgrammingLanguageCommandTest.java b/src/test/java/seedu/address/logic/commands/FilterProgrammingLanguageCommandTest.java
new file mode 100644
index 00000000000..63428f6f025
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FilterProgrammingLanguageCommandTest.java
@@ -0,0 +1,101 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.parser.FilterProgrammingLanguageCommandParser.createLanguages;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.CARL;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FilterProgrammingLanguageCommand}.
+ */
+public class FilterProgrammingLanguageCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() throws ParseException {
+ ProgrammingLanguageContainsKeywordsPredicate firstPredicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(createLanguages("Java"));
+ ProgrammingLanguageContainsKeywordsPredicate secondPredicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(createLanguages("Python"));
+
+ FilterProgrammingLanguageCommand filterProgrammingLanguageFirstCommand =
+ new FilterProgrammingLanguageCommand(firstPredicate);
+ FilterProgrammingLanguageCommand filterProgrammingLanguageSecondCommand =
+ new FilterProgrammingLanguageCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(filterProgrammingLanguageFirstCommand.equals(filterProgrammingLanguageFirstCommand));
+
+ // same values -> returns true
+ FilterProgrammingLanguageCommand filterProgrammingLanguageFirstCommandCopy =
+ new FilterProgrammingLanguageCommand(firstPredicate);
+ assertTrue(filterProgrammingLanguageFirstCommand.equals(filterProgrammingLanguageFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(filterProgrammingLanguageFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(filterProgrammingLanguageFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(filterProgrammingLanguageFirstCommand.equals(filterProgrammingLanguageSecondCommand));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noPersonFound() throws ParseException {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ ProgrammingLanguageContainsKeywordsPredicate predicate =
+ preparePredicate(" ");
+ FilterProgrammingLanguageCommand command = new FilterProgrammingLanguageCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_multipleKeywords_multiplePersonsFound() throws ParseException {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 4);
+ ProgrammingLanguageContainsKeywordsPredicate predicate = preparePredicate("Java java");
+ FilterProgrammingLanguageCommand command = new FilterProgrammingLanguageCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON, CARL, DANIEL), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void toStringMethod() throws ParseException {
+ ProgrammingLanguageContainsKeywordsPredicate predicate = new ProgrammingLanguageContainsKeywordsPredicate(
+ createLanguages("Java"));
+ FilterProgrammingLanguageCommand filterProgrammingLanguageCommand =
+ new FilterProgrammingLanguageCommand(predicate);
+ String expected = FilterProgrammingLanguageCommand.class.getCanonicalName()
+ + "{programming_language=" + predicate + "}";
+ assertEquals(expected, filterProgrammingLanguageCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code ProgrammingLanguageContainsKeywordsPredicate}.
+ */
+ private ProgrammingLanguageContainsKeywordsPredicate preparePredicate(String userInput) throws ParseException {
+ return new ProgrammingLanguageContainsKeywordsPredicate(createLanguages(userInput.split("\\s+")));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FilterSalaryCommandTest.java b/src/test/java/seedu/address/logic/commands/FilterSalaryCommandTest.java
new file mode 100644
index 00000000000..077788beb2f
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FilterSalaryCommandTest.java
@@ -0,0 +1,95 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryRange;
+
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FindSalaryCommand}.
+ */
+public class FilterSalaryCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ SalaryContainsKeywordsPredicate firstPredicate =
+ new SalaryContainsKeywordsPredicate(Collections.singletonList(new SalaryRange("2000")));
+ SalaryContainsKeywordsPredicate secondPredicate =
+ new SalaryContainsKeywordsPredicate(Collections.singletonList(new SalaryRange("2000-5000")));
+
+ FilterSalaryCommand filterSalaryFirstCommand = new FilterSalaryCommand(firstPredicate);
+ FilterSalaryCommand filterSalarySecondCommand = new FilterSalaryCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(filterSalaryFirstCommand.equals(filterSalaryFirstCommand));
+
+ // same values -> returns true
+ FilterSalaryCommand findSalaryFirstCommandCopy = new FilterSalaryCommand(firstPredicate);
+ assertTrue(filterSalaryFirstCommand.equals(findSalaryFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(filterSalaryFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(filterSalaryFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(filterSalaryFirstCommand.equals(filterSalarySecondCommand));
+ }
+
+
+ @Test
+ public void execute_oneSalary_multiplePersonsFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2);
+ SalaryContainsKeywordsPredicate predicate = preparePredicate(new SalaryRange(">=100"));
+ FilterSalaryCommand command = new FilterSalaryCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON), model.getFilteredPersonList());
+ }
+ @Test
+ public void execute_multipleSalaries_multiplePersonsFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2);
+ SalaryContainsKeywordsPredicate predicate = preparePredicate(new SalaryRange("1000"),
+ new SalaryRange(">=10000"));
+ FilterSalaryCommand command = new FilterSalaryCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON), model.getFilteredPersonList());
+ }
+
+
+ @Test
+ public void toStringMethod() {
+ SalaryContainsKeywordsPredicate predicate =
+ new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("5000")));
+ FilterSalaryCommand filterSalaryCommand = new FilterSalaryCommand(predicate);
+ String expected = FilterSalaryCommand.class.getCanonicalName() + "{salary=" + predicate + "}";
+ assertEquals(expected, filterSalaryCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code SalaryContainsKeywordsPredicate}.
+ */
+ private SalaryContainsKeywordsPredicate preparePredicate(SalaryRange... salaries) {
+ return new SalaryContainsKeywordsPredicate(Arrays.asList(salaries));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FilterTagCommandTest.java b/src/test/java/seedu/address/logic/commands/FilterTagCommandTest.java
new file mode 100644
index 00000000000..d14db71cc1c
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FilterTagCommandTest.java
@@ -0,0 +1,94 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.parser.FilterTagCommandParser.createTags;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FilterTagCommand}.
+ */
+public class FilterTagCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() throws ParseException {
+ TagContainsKeywordsPredicate firstPredicate =
+ new TagContainsKeywordsPredicate(createTags("first"));
+ TagContainsKeywordsPredicate secondPredicate =
+ new TagContainsKeywordsPredicate(createTags("second"));
+
+ FilterTagCommand findTagFirstCommand = new FilterTagCommand(firstPredicate);
+ FilterTagCommand findTagSecondCommand = new FilterTagCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findTagFirstCommand.equals(findTagFirstCommand));
+
+ // same values -> returns true
+ FilterTagCommand findTagFirstCommandCopy = new FilterTagCommand(firstPredicate);
+ assertTrue(findTagFirstCommand.equals(findTagFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(findTagFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(findTagFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(findTagFirstCommand.equals(findTagSecondCommand));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noPersonFound() throws ParseException {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ TagContainsKeywordsPredicate predicate = preparePredicate(" ");
+ FilterTagCommand command = new FilterTagCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void execute_multipleKeywords_multiplePersonsFound() throws ParseException {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
+ TagContainsKeywordsPredicate predicate = preparePredicate("friends friend");
+ FilterTagCommand command = new FilterTagCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON, DANIEL), model.getFilteredPersonList());
+ }
+
+ @Test
+ public void toStringMethod() throws ParseException {
+ TagContainsKeywordsPredicate predicate = new TagContainsKeywordsPredicate(createTags("friends"));
+ FilterTagCommand filterTagCommand = new FilterTagCommand(predicate);
+ String expected = FilterTagCommand.class.getCanonicalName() + "{tag=" + predicate + "}";
+ assertEquals(expected, filterTagCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
+ */
+ private TagContainsKeywordsPredicate preparePredicate(String userInput) throws ParseException {
+ return new TagContainsKeywordsPredicate(createTags(userInput.split("\\s+")));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..0537922ddba 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -18,7 +18,7 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.NameOrCompanyNameContainsKeywordsPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -29,10 +29,10 @@ public class FindCommandTest {
@Test
public void equals() {
- NameContainsKeywordsPredicate firstPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("first"));
- NameContainsKeywordsPredicate secondPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("second"));
+ NameOrCompanyNameContainsKeywordsPredicate firstPredicate =
+ new NameOrCompanyNameContainsKeywordsPredicate(Collections.singletonList("first"));
+ NameOrCompanyNameContainsKeywordsPredicate secondPredicate =
+ new NameOrCompanyNameContainsKeywordsPredicate(Collections.singletonList("second"));
FindCommand findFirstCommand = new FindCommand(firstPredicate);
FindCommand findSecondCommand = new FindCommand(secondPredicate);
@@ -57,7 +57,7 @@ public void equals() {
@Test
public void execute_zeroKeywords_noPersonFound() {
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
- NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ NameOrCompanyNameContainsKeywordsPredicate predicate = preparePredicate(" ");
FindCommand command = new FindCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
@@ -67,7 +67,7 @@ public void execute_zeroKeywords_noPersonFound() {
@Test
public void execute_multipleKeywords_multiplePersonsFound() {
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
- NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
+ NameOrCompanyNameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
FindCommand command = new FindCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
@@ -76,7 +76,8 @@ public void execute_multipleKeywords_multiplePersonsFound() {
@Test
public void toStringMethod() {
- NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
+ NameOrCompanyNameContainsKeywordsPredicate predicate =
+ new NameOrCompanyNameContainsKeywordsPredicate(Arrays.asList("keyword"));
FindCommand findCommand = new FindCommand(predicate);
String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, findCommand.toString());
@@ -85,7 +86,7 @@ public void toStringMethod() {
/**
* Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
*/
- private NameContainsKeywordsPredicate preparePredicate(String userInput) {
- return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
+ private NameOrCompanyNameContainsKeywordsPredicate preparePredicate(String userInput) {
+ return new NameOrCompanyNameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
}
}
diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
index 4904fc4352e..3b35c387c4c 100644
--- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
@@ -14,7 +14,7 @@ public class HelpCommandTest {
@Test
public void execute_help_success() {
- CommandResult expectedCommandResult = new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ CommandResult expectedCommandResult = new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
assertCommandSuccess(new HelpCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/SortCommandTest.java b/src/test/java/seedu/address/logic/commands/SortCommandTest.java
new file mode 100644
index 00000000000..87f3daf4444
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/SortCommandTest.java
@@ -0,0 +1,194 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.PersonCompanyNameComparator;
+import seedu.address.model.person.PersonInterviewTimeComparator;
+import seedu.address.model.person.PersonNameComparator;
+import seedu.address.model.person.PersonPriorityComparator;
+import seedu.address.model.person.PersonSalaryComparator;
+
+public class SortCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_validPriorityCliUnsortedList_success() {
+ Integer prefixToSort = 0; //sort by priority
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonPriorityComparator(false));
+
+ assertCommandSuccess(sortCommand, model, expectedMessage, expectedModel);
+
+ Integer prefixToSort2 = 0; //sort by priority
+ SortCommand sortCommand2 = new SortCommand(prefixToSort2, true);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonPriorityComparator(true));
+
+ assertCommandSuccess(sortCommand2, model, expectedMessage2, expectedModel2);
+ }
+ @Test
+ public void execute_validCompanyNameCliUnsortedList_success() {
+ Integer prefixToSort = 1; //sort by Company Name
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonCompanyNameComparator(false));
+
+ assertCommandSuccess(sortCommand, model, expectedMessage, expectedModel);
+
+ Integer prefixToSort2 = 1; //sort by Company Name
+ SortCommand sortCommand2 = new SortCommand(prefixToSort2, false);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonCompanyNameComparator(false));
+
+ assertCommandSuccess(sortCommand2, model, expectedMessage2, expectedModel2);
+ }
+
+ @Test
+ public void execute_validNameCliUnsortedList_success() {
+ Integer prefixToSort = 2; //sort by Name
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonNameComparator(false));
+
+ assertCommandSuccess(sortCommand, model, expectedMessage, expectedModel);
+
+ Integer prefixToSort2 = 2; //sort by Name
+ SortCommand sortCommand2 = new SortCommand(prefixToSort2, true);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonNameComparator(true));
+
+ assertCommandSuccess(sortCommand2, model, expectedMessage2, expectedModel2);
+ }
+
+ @Test
+ public void execute_validInterviewTimeCliUnsortedList_success() {
+ Integer prefixToSort = 3; //sort by InterviewTime
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonInterviewTimeComparator(false));
+
+ assertCommandSuccess(sortCommand, model, expectedMessage, expectedModel);
+
+ Integer prefixToSort2 = 3; //sort by InterviewTime
+ SortCommand sortCommand2 = new SortCommand(prefixToSort, true);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonInterviewTimeComparator(true));
+
+ assertCommandSuccess(sortCommand2, model, expectedMessage2, expectedModel2);
+ }
+
+ @Test
+ public void execute_validSalaryCliUnsortedList_success() {
+ Integer prefixToSort = 4; //sort by InterviewTime
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonSalaryComparator(false));
+
+ assertCommandSuccess(sortCommand, model, expectedMessage, expectedModel);
+
+ Integer prefixToSort2 = 4; //sort by InterviewTime
+ SortCommand sortCommand2 = new SortCommand(prefixToSort2, true);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonSalaryComparator(true));
+
+ assertCommandSuccess(sortCommand2, model, expectedMessage2, expectedModel2);
+ }
+
+ @Test
+ public void execute_validJobDifficultyCliUnsortedList_success() throws CommandException {
+ Integer prefixToSort = 5; //sort by Job Difficulty
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ String expectedMessage = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.updateSortedPersonList(new PersonSalaryComparator(false));
+
+ CommandResult result = sortCommand.execute(model);
+
+ assertEquals(result.getFeedbackToUser(), expectedMessage);
+
+ Integer prefixToSort2 = 5; //sort by Job Difficulty
+ SortCommand sortCommand2 = new SortCommand(prefixToSort2, true);
+
+ String expectedMessage2 = SortCommand.MESSAGE_LIST_SORTED_SUCCESS;
+
+ ModelManager expectedModel2 = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel2.updateSortedPersonList(new PersonSalaryComparator(true));
+
+ CommandResult result2 = sortCommand2.execute(model);
+
+ assertEquals(result2.getFeedbackToUser(), expectedMessage2);
+ }
+
+ @Test
+ public void execute_invalidCliUnsortedList_throwsCommandException() {
+ Integer prefixToSort = 6; //outside [0-5]
+ SortCommand sortCommand = new SortCommand(prefixToSort, false);
+
+ assertCommandFailure(sortCommand, model, Messages.MESSAGE_INVALID_SORT_COMMAND_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ SortCommand firstSort = new SortCommand(1, false);
+ SortCommand secondSort = new SortCommand(2, false);
+
+ // same object -> returns true
+ assertTrue(firstSort.equals(firstSort));
+ // same values -> returns true
+ SortCommand firstSortCopy = new SortCommand(1, false);
+ assertTrue(firstSort.equals(firstSortCopy));
+ // different types -> returns false
+ assertFalse(firstSort.equals(1));
+ // null -> returns false
+ assertFalse(firstSort.equals(null));
+ // different person -> returns false
+ assertFalse(firstSort.equals(secondSort));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..2c3c80ef4ce 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
@@ -3,9 +3,14 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.COMPANY_NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.COMPANY_NAME_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.INTERVIEWTIME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.INTERVIEWTIME_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_COMPANY_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
@@ -16,6 +21,7 @@
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
+import static seedu.address.logic.commands.CommandTestUtil.PROGRAMMING_LANG_DESC_DEFAULT;
import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
@@ -25,6 +31,7 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
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;
@@ -38,6 +45,7 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.AddCommand;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
@@ -53,23 +61,29 @@ public void parse_allFieldsPresent_success() {
Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build();
// whitespace only preamble
- assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
-
+ assertParseSuccess(parser, PREAMBLE_WHITESPACE + COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB
+ + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + INTERVIEWTIME_DESC_BOB + TAG_DESC_FRIEND + PROGRAMMING_LANG_DESC_DEFAULT,
+ new AddCommand(expectedPerson));
// multiple tags - all accepted
Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
.build();
- assertParseSuccess(parser,
- NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
+ assertParseSuccess(parser, COMPANY_NAME_DESC_BOB
+ + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + INTERVIEWTIME_DESC_BOB
+ + TAG_DESC_HUSBAND + TAG_DESC_FRIEND + PROGRAMMING_LANG_DESC_DEFAULT,
new AddCommand(expectedPersonMultipleTags));
}
@Test
public void parse_repeatedNonTagValue_failure() {
- String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ String validExpectedPersonString = COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ ADDRESS_DESC_BOB + TAG_DESC_FRIEND;
+ // multiple company names
+ assertParseFailure(parser, COMPANY_NAME_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_COMPANY_NAME));
+
// multiple names
assertParseFailure(parser, NAME_DESC_AMY + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
@@ -88,12 +102,18 @@ public void parse_repeatedNonTagValue_failure() {
// multiple fields repeated
assertParseFailure(parser,
- validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NAME_DESC_AMY + ADDRESS_DESC_AMY
- + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE));
+ validExpectedPersonString + COMPANY_NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY
+ + NAME_DESC_AMY + ADDRESS_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_COMPANY_NAME, PREFIX_NAME, PREFIX_ADDRESS,
+ PREFIX_EMAIL,
+ PREFIX_PHONE));
// invalid value followed by valid value
+ // invalid company name
+ assertParseFailure(parser, INVALID_COMPANY_NAME_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_COMPANY_NAME));
+
// invalid name
assertParseFailure(parser, INVALID_NAME_DESC + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
@@ -112,6 +132,10 @@ public void parse_repeatedNonTagValue_failure() {
// valid value followed by invalid value
+ // invalid company name
+ assertParseFailure(parser, validExpectedPersonString + INVALID_COMPANY_NAME_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_COMPANY_NAME));
+
// invalid name
assertParseFailure(parser, validExpectedPersonString + INVALID_NAME_DESC,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
@@ -133,7 +157,9 @@ public void parse_repeatedNonTagValue_failure() {
public void parse_optionalFieldsMissing_success() {
// zero tags
Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY,
+ assertParseSuccess(parser,
+ COMPANY_NAME_DESC_AMY + NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY
+ + ADDRESS_DESC_AMY + INTERVIEWTIME_DESC_AMY + PROGRAMMING_LANG_DESC_DEFAULT,
new AddCommand(expectedPerson));
}
@@ -164,33 +190,52 @@ public void parse_compulsoryFieldMissing_failure() {
@Test
public void parse_invalidValue_failure() {
+ // invalid company name
+ assertParseFailure(parser, INVALID_COMPANY_NAME_DESC + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, CompanyName.MESSAGE_CONSTRAINTS);
+
// invalid name
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
// invalid phone
- assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
// invalid email
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC
+ + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
// invalid address
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + INVALID_ADDRESS_DESC + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
// invalid tag
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + INTERVIEWTIME_DESC_BOB + INVALID_TAG_DESC + VALID_TAG_FRIEND,
+ Tag.MESSAGE_CONSTRAINTS);
// two invalid values, only first invalid value reported
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC,
- Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, COMPANY_NAME_DESC_BOB + INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + INVALID_ADDRESS_DESC, Name.MESSAGE_CONSTRAINTS);
// non-empty preamble
- assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
+ assertParseFailure(parser, PREAMBLE_NON_EMPTY + COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB
+ + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
+
+ @Test
+ public void parse_duplicatePrefixes_failure() {
+ assertParseFailure(parser, COMPANY_NAME_DESC_AMY + COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB
+ + EMAIL_DESC_BOB + ADDRESS_DESC_BOB, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_COMPANY_NAME));
+
+ }
+
+ @Test
+ public void parse_nonEmptyPreamble_failure() {
+ assertParseFailure(parser, PREAMBLE_NON_EMPTY + COMPANY_NAME_DESC_BOB + NAME_DESC_BOB + PHONE_DESC_BOB
+ + EMAIL_DESC_BOB + ADDRESS_DESC_BOB, String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddCommand.MESSAGE_USAGE));
+ }
}
diff --git a/src/test/java/seedu/address/logic/parser/AddResumeCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddResumeCommandParserTest.java
new file mode 100644
index 00000000000..f2604da7ef7
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/AddResumeCommandParserTest.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.AddResumeCommand;
+
+public class AddResumeCommandParserTest {
+ private AddResumeCommandParser parser = new AddResumeCommandParser();
+
+ @Test
+ public void parse_requiredFieldsMissing_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddResumeCommand.MESSAGE_USAGE));
+ }
+ @Test
+ public void parse_duplicatePrefixes_failure() {
+ assertParseFailure(parser, " n/Amy" + " n/Bob" + " a/test" + " p/123" + " e/test" + " cn/Google"
+ + " edu/NUS" + " s/3000",
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index 5a1ab3dbc0c..3be1e27738c 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -4,6 +4,9 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+import static seedu.address.logic.parser.FilterProgrammingLanguageCommandParser.createLanguages;
+import static seedu.address.logic.parser.FilterTagCommandParser.createTags;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
@@ -19,12 +22,21 @@
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FilterCommand;
+import seedu.address.logic.commands.FilterProgrammingLanguageCommand;
+import seedu.address.logic.commands.FilterSalaryCommand;
+import seedu.address.logic.commands.FilterTagCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;
+import seedu.address.model.person.NameOrCompanyNameContainsKeywordsPredicate;
import seedu.address.model.person.Person;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryRange;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.PersonBuilder;
import seedu.address.testutil.PersonUtil;
@@ -59,6 +71,7 @@ public void parseCommand_edit() throws Exception {
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
+ INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
+ System.out.println(command);
assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
}
@@ -73,7 +86,36 @@ public void parseCommand_find() throws Exception {
List keywords = Arrays.asList("foo", "bar", "baz");
FindCommand command = (FindCommand) parser.parseCommand(
FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
- assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
+ assertEquals(new FindCommand(new NameOrCompanyNameContainsKeywordsPredicate(keywords)), command);
+ }
+
+ @Test
+ public void parseCommand_filter_salary() throws Exception {
+ List keywords = Arrays.asList("2000", "9000-10000", "4000");
+ FilterSalaryCommand command = (FilterSalaryCommand) parser.parseCommand(
+ FilterCommand.COMMAND_WORD + " " + PREFIX_SALARY
+ + keywords.stream().collect(Collectors.joining(" ")));
+ assertEquals(new FilterSalaryCommand(new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("2000"),
+ new SalaryRange("9000-10000"), new SalaryRange("4000")))), command);
+ }
+ @Test
+ public void parseCommand_filter_tag() throws Exception {
+ List keywords = Arrays.asList("foo", "bar", "baz");
+ FilterTagCommand command = (FilterTagCommand) parser.parseCommand(
+ FilterTagCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
+ assertEquals(new FilterTagCommand(new TagContainsKeywordsPredicate(
+ createTags("foo", "bar", "baz"))), command);
+ }
+
+ @Test
+ public void parseCommand_filter_programmingLanguage() throws Exception {
+ List languages = Arrays.asList("Java", "C++", "Python");
+ FilterProgrammingLanguageCommand command = (FilterProgrammingLanguageCommand) parser.parseCommand(
+ FilterProgrammingLanguageCommand.COMMAND_WORD + " " + languages.stream()
+ .collect(Collectors.joining(" ")));
+ assertEquals(new FilterProgrammingLanguageCommand(
+ new ProgrammingLanguageContainsKeywordsPredicate(
+ createLanguages(languages.toArray(new String[0])))), command);
}
@Test
@@ -88,6 +130,12 @@ public void parseCommand_list() throws Exception {
assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
}
+ @Test
+ public void parseCommand_sort() throws Exception {
+ assertTrue(parser.parseCommand(SortCommand.COMMAND_WORD + " pri/") instanceof SortCommand);
+ assertTrue(parser.parseCommand(SortCommand.COMMAND_WORD + " pri/") instanceof SortCommand);
+ }
+
@Test
public void parseCommand_unrecognisedInput_throwsParseException() {
assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index cc7175172d4..4a3a53b0a8b 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -5,26 +5,41 @@
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.INFO_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.INFO_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.INTERVIEWTIME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.INTERVIEWTIME_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_INTERVIEWTIME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_SALARY_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.SALARY_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.SALARY_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INFO_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INTERVIEWTIME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SALARY_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
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_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
@@ -40,14 +55,17 @@
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
import seedu.address.testutil.EditPersonDescriptorBuilder;
public class EditCommandParserTest {
private static final String TAG_EMPTY = " " + PREFIX_TAG;
+ private static final String PROGRAMMING_LANG_EMPTY = " " + PREFIX_PROGRAMMING_LANGUAGE;
private static final String MESSAGE_INVALID_FORMAT =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
@@ -78,7 +96,7 @@ public void parse_invalidPreamble_failure() {
assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT);
// invalid prefix being parsed as preamble
- assertParseFailure(parser, "1 i/ string", MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "1 k/ string", MESSAGE_INVALID_FORMAT);
}
@Test
@@ -87,6 +105,9 @@ public void parse_invalidValue_failure() {
assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone
assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address
+ assertParseFailure(parser, "1" + INVALID_INTERVIEWTIME_DESC,
+ InterviewTime.MESSAGE_CONSTRAINTS); //invalid datetime
+ assertParseFailure(parser, "1" + INVALID_SALARY_DESC, Salary.MESSAGE_CONSTRAINTS); // invalid salary
assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag
// invalid phone followed by valid email
@@ -94,12 +115,16 @@ public void parse_invalidValue_failure() {
// while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited,
// parsing it together with a valid tag results in error
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND
+ + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY
+ + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND
+ + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
// multiple invalid values, but only the first invalid value is captured
- assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY,
+ assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC
+ + VALID_ADDRESS_AMY + VALID_PHONE_AMY + INVALID_SALARY_DESC + VALID_INFO_AMY,
Name.MESSAGE_CONSTRAINTS);
}
@@ -125,7 +150,6 @@ public void parse_someFieldsSpecified_success() {
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB)
.withEmail(VALID_EMAIL_AMY).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
-
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -156,6 +180,24 @@ public void parse_oneFieldSpecified_success() {
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
+ //dateTime
+ userInput = targetIndex.getOneBased() + INTERVIEWTIME_DESC_AMY;
+ descriptor = new EditPersonDescriptorBuilder().withInterviewTime(VALID_INTERVIEWTIME_AMY).build();
+ expectedCommand = new EditCommand(targetIndex, descriptor);
+ assertParseSuccess(parser, userInput, expectedCommand);
+ //assert(true);
+ // salary
+ userInput = targetIndex.getOneBased() + SALARY_DESC_AMY;
+ descriptor = new EditPersonDescriptorBuilder().withSalary(VALID_SALARY_AMY).build();
+ expectedCommand = new EditCommand(targetIndex, descriptor);
+ assert(true);
+
+ // info
+ userInput = targetIndex.getOneBased() + INFO_DESC_AMY;
+ descriptor = new EditPersonDescriptorBuilder().withInfo(VALID_INFO_AMY).build();
+ expectedCommand = new EditCommand(targetIndex, descriptor);
+ assert(true);
+
// tags
userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
@@ -181,11 +223,25 @@ public void parse_multipleRepeatedFields_failure() {
// mulltiple valid fields repeated
userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
- + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND
- + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND;
+ + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + INTERVIEWTIME_DESC_AMY
+ + TAG_DESC_FRIEND + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + INTERVIEWTIME_DESC_BOB
+ + TAG_DESC_HUSBAND;
assertParseFailure(parser, userInput,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_INTERVIEWTIME));
+
+ userInput = targetIndex.getOneBased()
+ + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
+ + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY
+ + EMAIL_DESC_AMY + SALARY_DESC_AMY + TAG_DESC_FRIEND
+ + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB
+ + SALARY_DESC_BOB + TAG_DESC_HUSBAND + INFO_DESC_BOB
+ + INFO_DESC_AMY;
+
+ assertParseFailure(parser, userInput,
+ Messages.getErrorMessageForDuplicatePrefixes(
+ PREFIX_PHONE, PREFIX_SALARY, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_INFO));
// multiple invalid values
userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + INVALID_ADDRESS_DESC + INVALID_EMAIL_DESC
@@ -199,7 +255,6 @@ public void parse_multipleRepeatedFields_failure() {
public void parse_resetTags_success() {
Index targetIndex = INDEX_THIRD_PERSON;
String userInput = targetIndex.getOneBased() + TAG_EMPTY;
-
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
diff --git a/src/test/java/seedu/address/logic/parser/FilterCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FilterCommandParserTest.java
new file mode 100644
index 00000000000..bc2a25efb9e
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FilterCommandParserTest.java
@@ -0,0 +1,81 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SALARY_RANGE_MAX;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FilterCommand;
+import seedu.address.logic.commands.FilterInterviewTimeCommand;
+import seedu.address.logic.commands.FilterSalaryCommand;
+import seedu.address.logic.commands.FilterTagCommand;
+import seedu.address.model.person.InterviewTime;
+import seedu.address.model.person.InterviewTimeContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryRange;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+public class FilterCommandParserTest {
+ private FilterCommandParser parser = new FilterCommandParser();
+
+ @Test
+ public void parse_moreThanOnePrefix_throwsParseException() {
+ assertParseFailure(parser, " " + PREFIX_SALARY + VALID_SALARY_RANGE_MAX + " " + PREFIX_TAG + VALID_TAG_FRIEND,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonEmptyPreamble_throwsParseException() {
+ assertParseFailure(parser, PREAMBLE_NON_EMPTY + " " + PREFIX_SALARY + VALID_SALARY_RANGE_MAX,
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_emptyArgs_throwsParseException() {
+ String args = "";
+ assert args.length() == 0;
+ assertParseFailure(parser, args, String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterSalaryCommand() {
+ FilterCommand expected =
+ new FilterSalaryCommand(new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("2000"),
+ new SalaryRange("5000-7000"))));
+ assertParseSuccess(parser, " " + PREFIX_SALARY + "2000 5000-7000", expected);
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterTagCommand() {
+ FilterCommand expected =
+ new FilterTagCommand(new TagContainsKeywordsPredicate(Arrays.asList(new Tag("friends"),
+ new Tag("owesMoney"))));
+ assertParseSuccess(parser, " " + PREFIX_TAG + "friends owesMoney", expected);
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterInterviewTimeCommand() {
+ FilterCommand expected =
+ new FilterInterviewTimeCommand(new InterviewTimeContainsKeywordsPredicate(
+ Arrays.asList(
+ Arrays.asList(null, new InterviewTime("020220220900")),
+ Arrays.asList(new InterviewTime("020520252200"), null),
+ Arrays.asList(new InterviewTime("050520220800"),
+ new InterviewTime("050520231800"))
+ )));
+ assertParseSuccess(parser, " " + PREFIX_INTERVIEWTIME + "before/020220220900 after/020520252200 "
+ + "from/050520220800-050520231800", expected);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParserTest.java
new file mode 100644
index 00000000000..83e9720ca48
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FilterProgrammingLanguageCommandParserTest.java
@@ -0,0 +1,34 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.logic.parser.FilterProgrammingLanguageCommandParser.createLanguages;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FilterProgrammingLanguageCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;
+
+public class FilterProgrammingLanguageCommandParserTest {
+ private FilterProgrammingLanguageCommandParser parser = new FilterProgrammingLanguageCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterProgrammingLanguageCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterTagCommand() throws ParseException {
+ // no leading and trailing whitespaces
+ FilterProgrammingLanguageCommand expectedFilterProgrammingLanguageCommand =
+ new FilterProgrammingLanguageCommand(new ProgrammingLanguageContainsKeywordsPredicate(
+ createLanguages("Java", "Python")));
+ assertParseSuccess(parser, "Java Python", expectedFilterProgrammingLanguageCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Java \n \t Python \t", expectedFilterProgrammingLanguageCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FilterSalaryCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FilterSalaryCommandParserTest.java
new file mode 100644
index 00000000000..0fae4709d39
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FilterSalaryCommandParserTest.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FilterSalaryCommand;
+import seedu.address.model.person.SalaryContainsKeywordsPredicate;
+import seedu.address.model.person.SalaryRange;
+
+
+public class FilterSalaryCommandParserTest {
+
+ private FilterSalaryCommandParser parser = new FilterSalaryCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterSalaryCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterSalaryCommand() {
+ // no leading and trailing whitespaces
+ FilterSalaryCommand expectedFilterSalaryCommand =
+ new FilterSalaryCommand(new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("2000"),
+ new SalaryRange("4000-9000"))));
+ assertParseSuccess(parser, "2000 4000-9000", expectedFilterSalaryCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n 2000 \n \t 4000-9000 \t", expectedFilterSalaryCommand);
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/FilterTagCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FilterTagCommandParserTest.java
new file mode 100644
index 00000000000..c10bb0d8226
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FilterTagCommandParserTest.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.logic.parser.FilterTagCommandParser.createTags;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FilterTagCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tag.TagContainsKeywordsPredicate;
+
+
+public class FilterTagCommandParserTest {
+
+ private FilterTagCommandParser parser = new FilterTagCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FilterTagCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFilterTagCommand() throws ParseException {
+ // no leading and trailing whitespaces
+ FilterTagCommand expectedFilterTagCommand =
+ new FilterTagCommand(new TagContainsKeywordsPredicate(createTags("Alice", "Bob")));
+ assertParseSuccess(parser, "Alice Bob", expectedFilterTagCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFilterTagCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index d92e64d12f9..eb73c8fe838 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -9,7 +9,7 @@
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.FindCommand;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.NameOrCompanyNameContainsKeywordsPredicate;
public class FindCommandParserTest {
@@ -24,7 +24,7 @@ public void parse_emptyArg_throwsParseException() {
public void parse_validArgs_returnsFindCommand() {
// no leading and trailing whitespaces
FindCommand expectedFindCommand =
- new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
+ new FindCommand(new NameOrCompanyNameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
// multiple whitespaces between keywords
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..d866260308e 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -9,11 +9,13 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
@@ -193,4 +195,72 @@ public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception {
assertEquals(expectedTagSet, actualTagSet);
}
+
+ @Test
+ public void parseSalaryRange_invalidArgs_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseSalaryRange("<=-1"));
+ }
+
+ @Test
+ public void parseProgrammingLanguage_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseProgrammingLanguage(null));
+ }
+
+ @Test
+ public void parseProgrammingLanguage_emptyString_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseProgrammingLanguage(""));
+ }
+
+ @Test
+ public void parseProgrammingLanguage_invalidValue_throwsParseException() {
+ // Testing with a language name containing invalid characters
+ assertThrows(ParseException.class, () -> ParserUtil.parseProgrammingLanguage("C++!"));
+ }
+
+ @Test
+ public void parseProgrammingLanguages_nullCollection_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseProgrammingLanguages(null));
+ }
+
+ @Test
+ public void parseProgrammingLanguages_emptyCollection_returnsEmptySet() throws ParseException {
+ Set result = ParserUtil.parseProgrammingLanguages(Collections.emptyList());
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void parseProgrammingLanguages_validCollection_returnsProgrammingLanguageSet() throws ParseException {
+ List validLanguages = Arrays.asList("Java", "Python", "JavaScript");
+ Set result = ParserUtil.parseProgrammingLanguages(validLanguages);
+ assertEquals(validLanguages.size(), result.size());
+ for (String language : validLanguages) {
+ assertTrue(result.contains(new ProgrammingLanguage(language)));
+ }
+ }
+
+ @Test
+ public void parsePriority_invalidArgs_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parsePriority("6"));
+ }
+
+ @Test
+ public void parsePriority_validArgs_returnsPriority() throws ParseException {
+ assertEquals(1, ParserUtil.parsePriority("1"));
+ }
+
+ @Test
+ public void parsePriority_invalidArgs2_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parsePriority("-1"));
+ }
+
+ @Test
+ public void parsePriority_validArgs2_returnsPriority() throws ParseException {
+ assertEquals(0, ParserUtil.parsePriority("0"));
+ }
+
+ @Test
+ public void parsePriority_invalidArgs3_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parsePriority("xx"));
+ }
+
}
diff --git a/src/test/java/seedu/address/logic/parser/SortCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SortCommandParserTest.java
new file mode 100644
index 00000000000..5763a4feed5
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/SortCommandParserTest.java
@@ -0,0 +1,49 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.logic.parser.SortCommandParser.MESSAGE_INVALID_INVERSE_COMMAND_KEYWORD;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.SortCommand;
+
+public class SortCommandParserTest {
+
+ private SortCommandParser parser = new SortCommandParser();
+
+ @Test
+ public void parse_validPrefix_returnsSortCommand() {
+ assertParseSuccess(parser, "pri/", new SortCommand(0, false));
+ assertParseSuccess(parser, "cn/", new SortCommand(1, false));
+ assertParseSuccess(parser, "n/", new SortCommand(2, false));
+ assertParseSuccess(parser, "tt/", new SortCommand(3, false));
+ assertParseSuccess(parser, "s/", new SortCommand(4, false));
+ assertParseSuccess(parser, "jd/", new SortCommand(5, false));
+ assertParseSuccess(parser, "pri/", new SortCommand(0, true));
+ assertParseSuccess(parser, "cn/", new SortCommand(1, true));
+ assertParseSuccess(parser, "n/", new SortCommand(2, true));
+ assertParseSuccess(parser, "tt/", new SortCommand(3, true));
+ assertParseSuccess(parser, "s/", new SortCommand(4, true));
+ assertParseSuccess(parser, "jd/", new SortCommand(5, true));
+ }
+
+ @Test
+ public void parse_invalidPrefix_throwsParseException() {
+ assertParseFailure(parser, "a", "Invalid command keyword for sort command");
+ }
+
+ @Test
+ public void parse_emptyInput_throwsParseException() {
+ assertParseFailure(parser, "", String.format(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE)));
+ }
+
+ @Test
+ public void parse_multipleArguments_throwsParseException() {
+ assertParseFailure(
+ parser, "pri/ com/", String.format(MESSAGE_INVALID_INVERSE_COMMAND_KEYWORD,
+ SortCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java
index 2cf1418d116..0c4f22a147d 100644
--- a/src/test/java/seedu/address/model/ModelManagerTest.java
+++ b/src/test/java/seedu/address/model/ModelManagerTest.java
@@ -129,4 +129,15 @@ public void equals() {
differentUserPrefs.setAddressBookFilePath(Paths.get("differentFilePath"));
assertFalse(modelManager.equals(new ModelManager(addressBook, differentUserPrefs)));
}
+
+ @Test
+ public void toString_validModelManager_returnsStringRepresentation() {
+ AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build();
+ UserPrefs userPrefs = new UserPrefs();
+ ModelManager modelManager = new ModelManager(addressBook, userPrefs);
+
+ String expectedString = String.format("%s, %s, %s", addressBook, userPrefs, modelManager
+ .getFilteredPersonList());
+ assertEquals(expectedString, modelManager.toString());
+ }
}
diff --git a/src/test/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..b0997afc197
--- /dev/null
+++ b/src/test/java/seedu/address/model/language/ProgrammingLanguageContainsKeywordsPredicateTest.java
@@ -0,0 +1,84 @@
+package seedu.address.model.language;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+public class ProgrammingLanguageContainsKeywordsPredicateTest {
+
+ @Test
+ public void equals() {
+ List firstLanguages = Collections.singletonList(new ProgrammingLanguage("Java"));
+ List secondLanguages = Collections.singletonList(new ProgrammingLanguage("C++"));
+
+ ProgrammingLanguageContainsKeywordsPredicate firstPredicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(firstLanguages);
+ ProgrammingLanguageContainsKeywordsPredicate secondPredicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(secondLanguages);
+
+ // same object -> returns true
+ Assertions.assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ ProgrammingLanguageContainsKeywordsPredicate firstPredicateCopy =
+ new ProgrammingLanguageContainsKeywordsPredicate(firstLanguages);
+ Assertions.assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ Assertions.assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ Assertions.assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ Assertions.assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_languageContainsKeywords_returnsTrue() {
+ // One keyword
+ List languages = Collections.singletonList(new ProgrammingLanguage("Java"));
+ ProgrammingLanguageContainsKeywordsPredicate predicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withProgrammingLanguages("Java", "C++").build()));
+
+ // Multiple keywords
+ languages = Collections.singletonList(new ProgrammingLanguage("C++"));
+ predicate = new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withProgrammingLanguages("Java", "C++").build()));
+
+ // Only one matching keyword
+ languages = Collections.singletonList(new ProgrammingLanguage("Java"));
+ predicate = new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withProgrammingLanguages("Java", "Python").build()));
+ }
+
+ @Test
+ public void test_languageDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ List languages = Collections.emptyList();
+ ProgrammingLanguageContainsKeywordsPredicate predicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ Assertions.assertFalse(predicate.test(new PersonBuilder().withProgrammingLanguages("Java", "C++").build()));
+
+ // Non-matching keyword
+ languages = Collections.singletonList(new ProgrammingLanguage("Python"));
+ predicate = new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ Assertions.assertFalse(predicate.test(new PersonBuilder().withProgrammingLanguages("Java", "C++").build()));
+ }
+
+ @SuppressWarnings("checkstyle:OperatorWrap")
+ @Test
+ public void toStringMethod() {
+ List languages = Collections.singletonList(new ProgrammingLanguage("Java"));
+ ProgrammingLanguageContainsKeywordsPredicate predicate =
+ new ProgrammingLanguageContainsKeywordsPredicate(languages);
+ String expected = ProgrammingLanguageContainsKeywordsPredicate.class.getCanonicalName()
+ + "{programming_language=[[Java]]}";
+ Assertions.assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/language/ProgrammingLanguageTest.java b/src/test/java/seedu/address/model/language/ProgrammingLanguageTest.java
new file mode 100644
index 00000000000..65108703df5
--- /dev/null
+++ b/src/test/java/seedu/address/model/language/ProgrammingLanguageTest.java
@@ -0,0 +1,69 @@
+package seedu.address.model.language;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class ProgrammingLanguageTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new ProgrammingLanguage(null));
+ }
+
+ @Test
+ public void constructor_invalidTagName_throwsIllegalArgumentException() {
+ String invalidLanguageName = "";
+ assertThrows(IllegalArgumentException.class, () -> new ProgrammingLanguage(invalidLanguageName));
+ }
+
+ @Test
+ public void isValidLanguageName() {
+ // null tag name
+ assertThrows(NullPointerException.class, () -> ProgrammingLanguage.isValidLanguageName(null));
+ }
+
+ @Test
+ public void constructor_validLanguageName_equals() {
+ // Two instances with the same valid language name should be equal
+ String languageName = "Java";
+ ProgrammingLanguage language1 = new ProgrammingLanguage(languageName);
+ ProgrammingLanguage language2 = new ProgrammingLanguage(languageName);
+ assertEquals(language1, language2);
+ }
+
+ @Test
+ public void isValidLanguageName_validLanguageName_returnsTrue() {
+ // Valid language name
+ String validLanguageName = "Java";
+ assertTrue(ProgrammingLanguage.isValidLanguageName(validLanguageName));
+ }
+
+ @Test
+ public void equals_sameInstance_returnsTrue() {
+ ProgrammingLanguage language = new ProgrammingLanguage("Java");
+ assertTrue(language.equals(language));
+ }
+
+ @Test
+ public void equals_nullObject_returnsFalse() {
+ ProgrammingLanguage language = new ProgrammingLanguage("Java");
+ assertFalse(language.equals(null));
+ }
+
+ @Test
+ public void equals_differentClass_returnsFalse() {
+ ProgrammingLanguage language = new ProgrammingLanguage("Java");
+ assertFalse(language.equals("Java"));
+ }
+
+ @Test
+ public void hashCode_sameInstance_returnsEqualHashCodes() {
+ ProgrammingLanguage language1 = new ProgrammingLanguage("Java");
+ ProgrammingLanguage language2 = new ProgrammingLanguage("Java");
+ assertEquals(language1.hashCode(), language2.hashCode());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/CompanyNameTest.java b/src/test/java/seedu/address/model/person/CompanyNameTest.java
new file mode 100644
index 00000000000..102c7860c9c
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/CompanyNameTest.java
@@ -0,0 +1,64 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class CompanyNameTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new CompanyName(null));
+ }
+
+ @Test
+ public void constructor_invalidName_throwsIllegalArgumentException() {
+ String invalidName = "";
+ assertThrows(IllegalArgumentException.class, () -> new CompanyName(invalidName));
+ }
+
+ @Test
+ public void isValidName() {
+ // null name
+ assertThrows(NullPointerException.class, () -> CompanyName.isValidCompanyName(null));
+
+ // invalid name
+ assertFalse(CompanyName.isValidCompanyName("")); // empty string
+ assertFalse(CompanyName.isValidCompanyName(" ")); // spaces only
+ assertFalse(CompanyName.isValidCompanyName("123456789 123456789 123456789 123456789 123456789 123456789 "
+ + "123456789 "
+ + "123456789 123456789 123456789 1")); // contains more than 100 chracters
+
+
+ // valid name
+ assertTrue(CompanyName.isValidCompanyName("Google")); // alphabets only
+ assertTrue(CompanyName.isValidCompanyName("711")); // numbers only
+ assertTrue(CompanyName.isValidCompanyName("Capital Land")); // with capital letters
+ // with capital letters and non-alphanumeric characters
+ assertTrue(CompanyName.isValidCompanyName("S&P 500"));
+ // long names
+ assertTrue(CompanyName.isValidCompanyName("Essilor International Compagnie Generale d'Optique SA"));
+ }
+
+ @Test
+ public void equals() {
+ CompanyName name = new CompanyName("Valid Name");
+
+ // same values -> returns true
+ assertTrue(name.equals(new CompanyName("Valid Name")));
+
+ // same object -> returns true
+ assertTrue(name.equals(name));
+
+ // null -> returns false
+ assertFalse(name.equals(null));
+
+ // different types -> returns false
+ assertFalse(name.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(name.equals(new CompanyName("Other Valid Name")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/EducationTest.java b/src/test/java/seedu/address/model/person/EducationTest.java
new file mode 100644
index 00000000000..9e8afa1a11c
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/EducationTest.java
@@ -0,0 +1,49 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.person.user.Education;
+
+public class EducationTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Education(null));
+ }
+ @Test
+ public void constructor_invalidName_throwsIllegalArgumentException() {
+ String invalidName = "";
+ assertThrows(IllegalArgumentException.class, () -> new Education(invalidName));
+ }
+ @Test
+ public void isValidEducation() {
+ assertTrue(Education.isValidEducation("AaBb123"));
+ assertTrue(Education.isValidEducation("A"));
+
+ assertFalse(Education.isValidEducation("!Invalid")); // Starts with a non-alphanumeric character
+ assertFalse(Education.isValidEducation("Contains!@#")); // Contains special characters
+ }
+ @Test
+ public void equals() {
+ Education name = new Education("Valid Name");
+
+ // same values -> returns true
+ assertTrue(name.equals(new Education("Valid Name")));
+
+ // same object -> returns true
+ assertTrue(name.equals(name));
+
+ // null -> returns false
+ assertFalse(name.equals(null));
+
+ // different types -> returns false
+ assertFalse(name.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(name.equals(new Education("Other Valid Name")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/InfoTest.java b/src/test/java/seedu/address/model/person/InfoTest.java
new file mode 100644
index 00000000000..bbf92e3c9be
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/InfoTest.java
@@ -0,0 +1,68 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class InfoTest {
+
+ @Test
+ public void emptyConstructorTest() {
+ // empty info constructor
+ Info info = new Info();
+ assertEquals("No additional info", info.value);
+ }
+
+ @Test
+ public void isValidInfo() {
+
+ // valid Info
+ assertTrue(Info.isValidInfo("123"));
+ assertTrue(Info.isValidInfo("Hello"));
+ assertTrue(Info.isValidInfo("My Name is bobby"));
+ assertTrue(Info.isValidInfo("I am a friend of a friend's friend of a friend"));
+ }
+
+ @Test
+ public void parseInfo() {
+ // Test with a string of letters;
+ Info info = new Info("Hello");
+ assertEquals("Hello", info.getInfo());
+
+ //Test with a string of numbers
+ info = new Info("122112");
+ assertEquals("122112", info.getInfo());
+ }
+
+ @Test
+ public void toStringTest() {
+ // Test with info as a string of letters
+ Info info = new Info("One hundred Thousand");
+ assertEquals("One hundred Thousand", info.toString());
+
+ // Test with info as a string of numbers
+ info = new Info("1233456");
+ assertEquals("1233456", info.toString());
+ }
+
+ @Test
+ public void equalsTest() {
+ Info info1 = new Info("Test");
+ Info info2 = new Info("Test");
+ String info3 = "Hello";
+
+ assertTrue(info1.equals(info1));
+ assertTrue(info1.equals(info2));
+ assertFalse(info1.equals(info3));
+ }
+
+ @Test
+ public void hashCodeTest() {
+ Info info1 = new Info("Test");
+ int hash1 = info1.hashCode();
+ int hash2 = "Test".hashCode();
+ assertEquals(hash1, hash2);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..290c7f0149c
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/InterviewTimeContainsKeywordsPredicateTest.java
@@ -0,0 +1,105 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+
+public class InterviewTimeContainsKeywordsPredicateTest {
+
+ @Test
+ public void equals() {
+ List> firstPredicateKeywordList =
+ Collections.singletonList(Arrays.asList(
+ new InterviewTime("121220210000"), null));
+ List> secondPredicateKeywordList = Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220210000")),
+ Arrays.asList(new InterviewTime("121220220000"), new InterviewTime("121220250000")),
+ Arrays.asList(new InterviewTime("121220270000"), null)
+ );
+
+ InterviewTimeContainsKeywordsPredicate firstPredicate =
+ new InterviewTimeContainsKeywordsPredicate(firstPredicateKeywordList);
+ InterviewTimeContainsKeywordsPredicate secondPredicate =
+ new InterviewTimeContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ InterviewTimeContainsKeywordsPredicate firstPredicateCopy =
+ new InterviewTimeContainsKeywordsPredicate(firstPredicateKeywordList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_interviewTimeRangeContainsKeywords_returnsTrue() {
+ // One interview time range keyword
+ InterviewTimeContainsKeywordsPredicate predicate = new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220220900")))
+ );
+ assertTrue(predicate.test(new PersonBuilder().withDateTime("120320190200").build()));
+
+ // Multiple interview time range keywords
+ predicate = new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220270900")),
+ Arrays.asList(new InterviewTime("121220230900"), new InterviewTime("121220260900")))
+ );
+ assertTrue(predicate.test(new PersonBuilder().withDateTime("120920250814").build()));
+
+
+ // Only one matching interview time range keyword
+ predicate = new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220200900")),
+ Arrays.asList(new InterviewTime("121220230900"), new InterviewTime("121220260900")))
+ );
+ assertTrue(predicate.test(new PersonBuilder().withDateTime("120920250814").build()));
+
+ }
+ @Test
+ public void test_interviewTimeRangeDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ InterviewTimeContainsKeywordsPredicate predicate = new InterviewTimeContainsKeywordsPredicate(
+ Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withDateTime("120920250814").build()));
+
+ // Non-matching keyword
+ predicate = new InterviewTimeContainsKeywordsPredicate(Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220200900")),
+ Arrays.asList(new InterviewTime("121220230900"), new InterviewTime("121220260900")))
+ );
+ assertFalse(predicate.test(new PersonBuilder().withDateTime("120920280814").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List> keywords = Arrays.asList(
+ Arrays.asList(null, new InterviewTime("121220210000")),
+ Arrays.asList(new InterviewTime("121220220000"), new InterviewTime("121220250000")),
+ Arrays.asList(new InterviewTime("121220270000"), null)
+ );
+ InterviewTimeContainsKeywordsPredicate predicate = new InterviewTimeContainsKeywordsPredicate(keywords);
+
+ String expected =
+ InterviewTimeContainsKeywordsPredicate.class.getCanonicalName()
+ + "{interviewTimes=" + keywords + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/InterviewTimeTest.java b/src/test/java/seedu/address/model/person/InterviewTimeTest.java
new file mode 100644
index 00000000000..e3b82fa48e8
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/InterviewTimeTest.java
@@ -0,0 +1,112 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+public class InterviewTimeTest {
+ @Test
+ public void constructor_null_doesNotThrowException() {
+ InterviewTime interviewTime = new InterviewTime(null);
+ assertNull(interviewTime.getDateTime());
+ }
+
+ @Test
+ public void constructor_invalidDateTime_throwsDateTimeParseException() {
+ String invalidDateTime = "dfbnkasljbjbe";
+ String invalidDateTime2 = "140020240402";
+ assertThrows(IllegalArgumentException.class, () -> new InterviewTime(invalidDateTime));
+ assertThrows(IllegalArgumentException.class, () -> new InterviewTime(invalidDateTime2));
+ }
+
+ @Test
+ public void testIsWithinInterviewTimeRange() {
+ InterviewTime dateTimeAfterRange = new InterviewTime("121120271400");
+ InterviewTime dateTimeBeforeRange = new InterviewTime("121120201400");
+ InterviewTime dateTimeInRange = new InterviewTime("121120231400");
+ InterviewTime dateTimeEqualAfterDate = new InterviewTime("011120231400");
+ InterviewTime dateTimeEqualBeforeDate = new InterviewTime("121220240300");
+
+ // Interview time ranges
+ List wrongSize = Arrays.asList(null, null, null);
+ List invalidInput = Arrays.asList(null, null);
+ List validBefore = Arrays.asList(null, new InterviewTime("121220230900"));
+ List validAfter = Arrays.asList(new InterviewTime("011120231400"), null);
+ List validRange = Arrays.asList(new InterviewTime("011120231400"),
+ new InterviewTime("121220240300"));
+
+ // Assertion error thrown
+ try {
+ dateTimeInRange.isWithinInterviewTimeRange(wrongSize);
+ assert(false);
+ } catch (AssertionError e) {
+ assertEquals("InterviewTime range should be of size 2", e.getMessage());
+ }
+ try {
+ dateTimeInRange.isWithinInterviewTimeRange(invalidInput);
+ assert(false);
+ } catch (AssertionError e) {
+ assertEquals("InterviewTime range cannot cannot contain more than 1 null Object", e.getMessage());
+ }
+
+ // Return false
+ assertFalse(dateTimeAfterRange.isWithinInterviewTimeRange(validBefore)); // dateTime falls after range
+ assertFalse(dateTimeAfterRange.isWithinInterviewTimeRange(validRange)); // dateTime falls after range
+ assertFalse(dateTimeBeforeRange.isWithinInterviewTimeRange(validAfter)); // dateTime falls before range
+ assertFalse(dateTimeBeforeRange.isWithinInterviewTimeRange(validRange)); // dateTime falls before range
+
+ // Return true
+ assertTrue(dateTimeAfterRange.isWithinInterviewTimeRange(validAfter));
+ assertTrue(dateTimeBeforeRange.isWithinInterviewTimeRange(validBefore));
+ assertTrue(dateTimeInRange.isWithinInterviewTimeRange(validRange));
+ assertTrue(dateTimeEqualAfterDate.isWithinInterviewTimeRange(validRange));
+ assertTrue(dateTimeEqualBeforeDate.isWithinInterviewTimeRange(validRange));
+
+
+
+ }
+ @Test
+ public void equals() {
+ InterviewTime dateTime = new InterviewTime("121220221400");
+
+ // same values -> returns true
+ assertTrue(dateTime.equals(new InterviewTime("121220221400")));
+
+ // same object -> returns true
+ assertTrue(dateTime.equals(dateTime));
+
+ // null -> returns false
+ assertFalse(dateTime.equals(null));
+
+ // different types -> returns false
+ assertFalse(dateTime.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(dateTime.equals(new Address("111220221400")));
+ }
+ @Test
+ public void parseInterviewTime() {
+ InterviewTime dateTime = new InterviewTime("121220221400");
+ assertEquals("2022-12-12T14:00", dateTime.getDateTime().toString());
+ }
+
+ @Test
+ public void hashcode() {
+ InterviewTime dateTime = new InterviewTime("121220221400");
+
+ //different values -> different hashcode
+ assertFalse(dateTime.hashCode() == new InterviewTime("121120221400").hashCode());
+ }
+ @Test
+ public void toStringTest() {
+ InterviewTime dateTime = new InterviewTime("121220221400");
+ assertEquals("December 12, 2022 02:00 PM", dateTime.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/JobDifficultyTest.java b/src/test/java/seedu/address/model/person/JobDifficultyTest.java
new file mode 100644
index 00000000000..126c9dd4b22
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/JobDifficultyTest.java
@@ -0,0 +1,58 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class JobDifficultyTest {
+
+ @Test
+ public void testGetDifficulty() {
+ // Test with a company that is in the JobDifficultyCompanyList and a salary of 1500
+ JobDifficulty jobDifficulty1 = new JobDifficulty(new CompanyName("oracle"), new Salary("1500"));
+ int expectedDifficulty1 = JobDifficultyCompanyList.getJobDifficultyCompanyList().get("oracle") + 5;
+ assertTrue(jobDifficulty1.getDifficulty() >= 70);
+
+ // Test with a company that is not in the JobDifficultyCompanyList and a salary of 3000
+ JobDifficulty jobDifficulty2 = new JobDifficulty(new CompanyName("unknown"), new Salary("3000"));
+ int actualDifficulty2 = jobDifficulty2.getDifficulty();
+ assert(actualDifficulty2 >= 20 && actualDifficulty2 <= 70);
+
+ // Test with a company that is in the JobDifficultyCompanyList and a salary of 5000
+ JobDifficulty jobDifficulty3 = new JobDifficulty(new CompanyName("ibm"), new Salary("5000"));
+ int expectedDifficulty3 = JobDifficultyCompanyList.getJobDifficultyCompanyList().get("ibm") + 40;
+ if (expectedDifficulty3 > 100) {
+ expectedDifficulty3 = 100;
+ }
+ assertEquals(expectedDifficulty3, jobDifficulty3.getDifficulty());
+
+ // Test with a company that is not in the JobDifficultyCompanyList and a salary of 4000
+ JobDifficulty jobDifficulty4 = new JobDifficulty(new CompanyName("unknown"), new Salary("4000"));
+ int actualDifficulty4 = jobDifficulty4.getDifficulty();
+ assert(actualDifficulty4 >= 30 && actualDifficulty4 <= 70);
+
+ // Test with a company that is not in the JobDifficultyCompanyList and a salary of 10000
+ JobDifficulty jobDifficulty5 = new JobDifficulty(new CompanyName("unknown"), new Salary("10000"));
+ int actualDifficulty5 = jobDifficulty5.getDifficulty();
+ assert(actualDifficulty5 >= 60 && actualDifficulty5 <= 100);
+ }
+
+ @Test
+ public void testToString() {
+ JobDifficulty jobDifficulty1 = new JobDifficulty(new CompanyName("oracle"), new Salary("1500"));
+ assertEquals(Integer.toString(jobDifficulty1.getDifficulty()), jobDifficulty1.toString());
+
+ JobDifficulty jobDifficulty2 = new JobDifficulty(new CompanyName("unknown"), new Salary("3000"));
+ assertEquals(Integer.toString(jobDifficulty2.getDifficulty()), jobDifficulty2.toString());
+
+ JobDifficulty jobDifficulty3 = new JobDifficulty(new CompanyName("ibm"), new Salary("5000"));
+ assertEquals(Integer.toString(jobDifficulty3.getDifficulty()), jobDifficulty3.toString());
+
+ JobDifficulty jobDifficulty4 = new JobDifficulty(new CompanyName("unknown"), new Salary("4000"));
+ assertEquals(Integer.toString(jobDifficulty4.getDifficulty()), jobDifficulty4.toString());
+
+ JobDifficulty jobDifficulty5 = new JobDifficulty(new CompanyName("unknown"), new Salary("10000"));
+ assertEquals(Integer.toString(jobDifficulty5.getDifficulty()), jobDifficulty5.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonCompanyNameComparatorTest.java b/src/test/java/seedu/address/model/person/PersonCompanyNameComparatorTest.java
new file mode 100644
index 00000000000..335f57d9745
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonCompanyNameComparatorTest.java
@@ -0,0 +1,32 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import org.junit.jupiter.api.Test;
+
+public class PersonCompanyNameComparatorTest {
+ @Test
+ public void checkOrder() {
+ PersonCompanyNameComparator comparator = new PersonCompanyNameComparator(false);
+ //test more than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test less than
+ assertTrue(comparator.compare(BENSON, ALICE) <= -1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonCompanyNameComparator comparator = new PersonCompanyNameComparator(true);
+ //test more than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test less than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+
+}
diff --git a/src/test/java/seedu/address/model/person/PersonInterviewTimeComparatorTest.java b/src/test/java/seedu/address/model/person/PersonInterviewTimeComparatorTest.java
new file mode 100644
index 00000000000..4478d1391cb
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonInterviewTimeComparatorTest.java
@@ -0,0 +1,48 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.language.ProgrammingLanguage;
+import seedu.address.model.tag.Tag;
+
+public class PersonInterviewTimeComparatorTest {
+
+ private static final CompanyName VALID_COMPANY_NAME = BENSON.getCompanyName();
+ private static final Name VALID_NAME = BENSON.getName();
+ private static final Phone VALID_PHONE = BENSON.getPhone();
+ private static final Email VALID_EMAIL = BENSON.getEmail();
+ private static final Address VALID_ADDRESS = BENSON.getAddress();
+ private static final InterviewTime VALID_INTERVIEWTIME = BENSON.getDateTime();
+ private static final Salary VALID_SALARY = BENSON.getSalary();
+ private static final Info VALID_INFO = BENSON.getInfo();
+ private static final Set VALID_PROGRAMMING_LANG = BENSON.getProgrammingLanguages();
+ private static final Set VALID_TAGS = BENSON.getTags();
+
+ @Test
+ public void checkOrder() {
+ PersonInterviewTimeComparator comparator = new PersonInterviewTimeComparator(false);
+ //test earlier than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test later than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonInterviewTimeComparator comparator = new PersonInterviewTimeComparator(true);
+ //test earlier than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test later than
+ assertTrue(comparator.compare(BENSON, ALICE) <= -1);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonJobDifficultyComparatorTest.java b/src/test/java/seedu/address/model/person/PersonJobDifficultyComparatorTest.java
new file mode 100644
index 00000000000..8e7bf04b31c
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonJobDifficultyComparatorTest.java
@@ -0,0 +1,32 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import org.junit.jupiter.api.Test;
+
+public class PersonJobDifficultyComparatorTest {
+
+ @Test
+ public void checkOrder() {
+ PersonJobDifficultyComparator comparator = new PersonJobDifficultyComparator(false);
+ //test more than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test less than
+ assertTrue(comparator.compare(BENSON, ALICE) <= -1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonJobDifficultyComparator comparator = new PersonJobDifficultyComparator(true);
+ //test more than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test less than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonNameComparatorTest.java b/src/test/java/seedu/address/model/person/PersonNameComparatorTest.java
new file mode 100644
index 00000000000..5fcf94764be
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonNameComparatorTest.java
@@ -0,0 +1,31 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import org.junit.jupiter.api.Test;
+
+public class PersonNameComparatorTest {
+ @Test
+ public void checkOrder() {
+ PersonNameComparator comparator = new PersonNameComparator(false);
+ //test less than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test more than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonNameComparator comparator = new PersonNameComparator(true);
+ //test less than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test more than
+ assertTrue(comparator.compare(BENSON, ALICE) <= -1);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonPriorityComparatorTest.java b/src/test/java/seedu/address/model/person/PersonPriorityComparatorTest.java
new file mode 100644
index 00000000000..a9bbc7cc0ef
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonPriorityComparatorTest.java
@@ -0,0 +1,32 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import org.junit.jupiter.api.Test;
+
+public class PersonPriorityComparatorTest {
+
+ @Test
+ public void checkOrder() {
+ PersonPriorityComparator comparator = new PersonPriorityComparator(false);
+ //test more than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test less than
+ assertTrue(comparator.compare(BENSON, ALICE) <= -1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonPriorityComparator comparator = new PersonPriorityComparator(true);
+ //test less than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test more than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonSalaryComparatorTest.java b/src/test/java/seedu/address/model/person/PersonSalaryComparatorTest.java
new file mode 100644
index 00000000000..82c24aba8cd
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/PersonSalaryComparatorTest.java
@@ -0,0 +1,31 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+
+import org.junit.jupiter.api.Test;
+
+public class PersonSalaryComparatorTest {
+ @Test
+ public void checkOrder() {
+ PersonSalaryComparator comparator = new PersonSalaryComparator(false);
+ //test less than
+ assertTrue(comparator.compare(ALICE, BENSON) <= -1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test more than
+ assertTrue(comparator.compare(BENSON, ALICE) >= 1);
+ }
+
+ @Test
+ public void checkReverseOrder() {
+ PersonSalaryComparator comparator = new PersonSalaryComparator(true);
+ //test less than
+ assertTrue(comparator.compare(ALICE, BENSON) >= 1);
+ //test equals
+ assertTrue(comparator.compare(ALICE, ALICE) == 0);
+ //test more than
+ assertTrue(comparator.compare(BENSON, ALICE) <= 1);
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java
index 31a10d156c9..85146a2d40f 100644
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ b/src/test/java/seedu/address/model/person/PersonTest.java
@@ -2,11 +2,16 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INFO_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INTERVIEWTIME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SALARY_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
@@ -34,7 +39,11 @@ public void isSamePerson() {
// same name, all other attributes different -> returns true
Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build();
+ .withAddress(VALID_ADDRESS_BOB)
+ .withDateTime(VALID_INTERVIEWTIME_BOB)
+ .withSalary(VALID_SALARY_BOB)
+ .withInfo(VALID_INFO_BOB)
+ .withTags(VALID_TAG_HUSBAND).build();
assertTrue(ALICE.isSamePerson(editedAlice));
// different name, all other attributes same -> returns false
@@ -85,15 +94,56 @@ public void equals() {
editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(ALICE.equals(editedAlice));
+ // different interview time -> returns true
+ editedAlice = new PersonBuilder(ALICE).withDateTime(VALID_INTERVIEWTIME_BOB).build();
+ assertTrue(ALICE.equals(editedAlice));
+
+ // different salary -> return true
+ editedAlice = new PersonBuilder(ALICE).withSalary(VALID_SALARY_BOB).build();
+ assertTrue(ALICE.equals(editedAlice));
+
+ // different info -> returns true
+ editedAlice = new PersonBuilder(ALICE).withInfo(VALID_INFO_BOB).build();
+ assertTrue(ALICE.equals(editedAlice));
+
// different tags -> returns false
editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build();
assertFalse(ALICE.equals(editedAlice));
+
+ // different Priority -> returns True
+ editedAlice = new PersonBuilder(ALICE).withPriority(1).build();
+ assertTrue(ALICE.equals(editedAlice));
+ }
+
+ @Test
+ public void hashCodeTest() {
+ Person person1 = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
+ .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withSalary(VALID_SALARY_BOB)
+ .withInfo(VALID_INFO_BOB).withTags(VALID_TAG_HUSBAND).build();
+ Person person2 = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
+ .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withSalary(VALID_SALARY_BOB)
+ .withInfo(VALID_INFO_BOB).withTags(VALID_TAG_HUSBAND).build();
+ assertEquals(person1.hashCode(), person2.hashCode());
+
+ person2 = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_BOB)
+ .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withSalary(VALID_SALARY_BOB)
+ .withInfo(VALID_INFO_BOB).withTags(VALID_TAG_HUSBAND).build();
+
+ assertNotEquals(person1.hashCode(), person2.hashCode());
}
@Test
public void toStringMethod() {
- String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
- + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}";
+ String expected = Person.class.getCanonicalName() + "{company name=" + ALICE.getCompanyName()
+ + ", name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
+ + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress()
+ + ", interview-time=" + ALICE.getDateTime()
+ + ", salary=" + ALICE.getSalary()
+ + ", info=" + ALICE.getInfo()
+ + ", tags=" + ALICE.getTags()
+ + ", programming-languages=" + ALICE.getProgrammingLanguages()
+ + ", priority=" + ALICE.getPriority()
+ + "}";
assertEquals(expected, ALICE.toString());
}
}
diff --git a/src/test/java/seedu/address/model/person/SalaryContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/SalaryContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..d5224643614
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/SalaryContainsKeywordsPredicateTest.java
@@ -0,0 +1,86 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PersonBuilder;
+
+
+
+
+public class SalaryContainsKeywordsPredicateTest {
+
+ @Test
+ public void equals() {
+ List firstPredicateKeywordList = Collections.singletonList(new SalaryRange("1000"));
+ List secondPredicateKeywordList = Arrays.asList(new SalaryRange("1000"),
+ new SalaryRange("5000-8000"));
+
+ SalaryContainsKeywordsPredicate firstPredicate = new SalaryContainsKeywordsPredicate(firstPredicateKeywordList);
+ SalaryContainsKeywordsPredicate secondPredicate =
+ new SalaryContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ SalaryContainsKeywordsPredicate firstPredicateCopy =
+ new SalaryContainsKeywordsPredicate(firstPredicateKeywordList);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_salaryContainsKeywords_returnsTrue() {
+ // One salary keyword
+ SalaryContainsKeywordsPredicate predicate = new SalaryContainsKeywordsPredicate(
+ Collections.singletonList(new SalaryRange("1000")));
+ assertTrue(predicate.test(new PersonBuilder().withSalary("1000-2000").build()));
+
+ // Multiple salary keywords
+ predicate = new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("1500"),
+ new SalaryRange("1000")));
+ assertTrue(predicate.test(new PersonBuilder().withSalary("1000-2000").build()));
+
+
+ // Only one matching salary keyword
+ predicate = new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("1000"),
+ new SalaryRange("3000")));
+ assertTrue(predicate.test(new PersonBuilder().withSalary("1000-2000").build()));
+
+ }
+ @Test
+ public void test_salaryDoesNotContainKeywords_returnsFalse() {
+ // Zero keywords
+ SalaryContainsKeywordsPredicate predicate = new SalaryContainsKeywordsPredicate(Collections.emptyList());
+ assertFalse(predicate.test(new PersonBuilder().withSalary("1000-2000").build()));
+
+ // Non-matching keyword
+ predicate = new SalaryContainsKeywordsPredicate(Arrays.asList(new SalaryRange("5000")));
+ assertFalse(predicate.test(new PersonBuilder().withSalary("1000-2000").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ List keywords = List.of(new SalaryRange("1000"), new SalaryRange("2000-5000"));
+ SalaryContainsKeywordsPredicate predicate = new SalaryContainsKeywordsPredicate(keywords);
+
+ String expected = SalaryContainsKeywordsPredicate.class.getCanonicalName() + "{salaries=" + keywords + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/SalaryRangeTest.java b/src/test/java/seedu/address/model/person/SalaryRangeTest.java
new file mode 100644
index 00000000000..55fee767fee
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/SalaryRangeTest.java
@@ -0,0 +1,104 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+
+
+public class SalaryRangeTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Salary(null));
+ }
+
+ @Test
+ public void isValidSalaryRange() {
+ // Valid salary ranges
+ assertTrue(SalaryRange.isValidSalaryRange("0"));
+ assertTrue(SalaryRange.isValidSalaryRange("2495762"));
+ assertTrue(SalaryRange.isValidSalaryRange("22930-1003874"));
+ assertTrue(SalaryRange.isValidSalaryRange(">=0"));
+ assertTrue(SalaryRange.isValidSalaryRange("<=2147483647"));
+
+ // Invalid salary ranges
+ assertFalse(SalaryRange.isValidSalaryRange(""));
+ assertFalse(SalaryRange.isValidSalaryRange(" "));
+ assertFalse(SalaryRange.isValidSalaryRange("5>6"));
+ assertFalse(SalaryRange.isValidSalaryRange("09<234"));
+ assertFalse(SalaryRange.isValidSalaryRange("--80"));
+ assertFalse(SalaryRange.isValidSalaryRange("80--80"));
+ assertFalse(SalaryRange.isValidSalaryRange("asfkjb"));
+ assertFalse(SalaryRange.isValidSalaryRange("2147483648"));
+ assertFalse(SalaryRange.isValidSalaryRange("-1-4"));
+ assertFalse(SalaryRange.isValidSalaryRange("1--4"));
+ assertFalse(SalaryRange.isValidSalaryRange("1-asovn"));
+ assertFalse(SalaryRange.isValidSalaryRange(">=-1"));
+ assertFalse(SalaryRange.isValidSalaryRange(">=asokc"));
+ assertFalse(SalaryRange.isValidSalaryRange("<=-1"));
+ assertFalse(SalaryRange.isValidSalaryRange("<=adv^aeo"));
+
+ }
+ @Test
+ public void isWithinSalaryRange() {
+ SalaryRange salaryRange = new SalaryRange("2000-8000");
+ Salary lessThanRange = new Salary("100-300");
+ Salary moreThanRange = new Salary("8500-10000");
+ Salary withinRange1 = new Salary("1000-3000");
+ Salary withinRange2 = new Salary("3000-9000");
+
+ // Salaries not within salary range
+ assertFalse(salaryRange.isWithinSalaryRange(lessThanRange));
+ assertFalse(salaryRange.isWithinSalaryRange(moreThanRange));
+
+ // Salaries within salary range
+ assertTrue(salaryRange.isWithinSalaryRange(withinRange1));
+ assertTrue(salaryRange.isWithinSalaryRange(withinRange2));
+ }
+
+ @Test
+ public void toStringTest() {
+ // Test with a salary range
+ SalaryRange salaryRange = new SalaryRange("4000-5000");
+ assertEquals("4000-5000", salaryRange.toString());
+
+ // Test with a single salary range
+ salaryRange = new SalaryRange("6000");
+ assertEquals("6000", salaryRange.toString());
+
+ // Test with max salary
+ salaryRange = new SalaryRange("<=80000");
+ assertEquals("<=80000", salaryRange.toString());
+
+ // Test with min salary
+ salaryRange = new SalaryRange(">=800920");
+ assertEquals(">=800920", salaryRange.toString());
+ }
+
+ @Test
+ public void equalsTest() {
+ SalaryRange singleValue = new SalaryRange("6000");
+ SalaryRange toMaxRange1 = new SalaryRange("5000-2147483647");
+ SalaryRange toMaxRange2 = new SalaryRange("5000-2147483647");
+ SalaryRange minRange = new SalaryRange(">=5000");
+ SalaryRange maxRange = new SalaryRange("<=4000");
+
+ // same object -> returns true
+ assertTrue(singleValue.equals(singleValue));
+ // same range -> returns true
+ assertTrue(toMaxRange1.equals(toMaxRange2));
+ assertTrue(toMaxRange1.equals(minRange));
+
+ // different type -> returns false
+ assertFalse(singleValue.equals(9));
+ // null -> returns false
+ assertFalse(singleValue.equals(null));
+ // different range -> returns false
+ assertFalse(toMaxRange1.equals(singleValue));
+ assertFalse(toMaxRange1.equals(maxRange));
+
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/SalaryTest.java b/src/test/java/seedu/address/model/person/SalaryTest.java
new file mode 100644
index 00000000000..a1101172932
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/SalaryTest.java
@@ -0,0 +1,105 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SalaryTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Salary(null));
+ }
+
+ @Test
+ public void constructor_invalidSalary_throwsIllegalArgumentException() {
+ String invalidSalary = "dsadas";
+ String invalidSalary2 = "42389408320478923432423";
+ String invalidSalary3 = "42389408320478923432423-438247328947328974893273482394";
+ assertThrows(IllegalArgumentException.class, () -> new Salary(invalidSalary));
+ assertThrows(IllegalArgumentException.class, () -> new Salary(invalidSalary2));
+ assertThrows(IllegalArgumentException.class, () -> new Salary(invalidSalary3));
+ }
+
+ @Test
+ public void isValidSalary() {
+ // valid salaries
+ assertTrue(Salary.isValidSalary("0"));
+ assertTrue(Salary.isValidSalary("1"));
+ assertTrue(Salary.isValidSalary("99999999"));
+ assertTrue(Salary.isValidSalary("100-10000"));
+ assertTrue(Salary.isValidSalary("9999999-10000"));
+
+ // invalid salaries
+ assertFalse(Salary.isValidSalary(""));
+ assertFalse(Salary.isValidSalary(" "));
+ assertFalse(Salary.isValidSalary("-1"));
+ assertFalse(Salary.isValidSalary("-1000"));
+ assertFalse(Salary.isValidSalary("-1-1221"));
+ assertFalse(Salary.isValidSalary("-1--1212121"));
+ assertFalse(Salary.isValidSalary("dsadas"));
+ assertFalse(Salary.isValidSalary("5000-4000-3000"));
+ assertFalse(Salary.isValidSalary("100-dfadfdsfsdfds"));
+ assertFalse(Salary.isValidSalary("42389408320478923432423"));
+ }
+
+ @Test
+ public void parseSalary() {
+ // Test with a salary range where the first number is larger than the second
+ Salary salary = new Salary("5000-4000");
+ assertEquals(4000, salary.getSalary1());
+ assertEquals(5000, salary.getSalary2());
+ assertTrue(salary.isRange());
+
+ // Test with a salary range where the first number is smaller than the second
+ salary = new Salary("3000-4000");
+ assertEquals(3000, salary.getSalary1());
+ assertEquals(4000, salary.getSalary2());
+ assertTrue(salary.isRange());
+
+ // Test with a single salary
+ salary = new Salary("6000");
+ assertEquals(6000, salary.getSalary1());
+ assertEquals(6000, salary.getSalary2());
+ assertFalse(salary.isRange());
+ }
+
+ @Test
+ public void toStringTest() {
+ // Test with a salary range
+ Salary salary = new Salary("4000-5000");
+ assertEquals("4000-5000", salary.toString());
+
+ // Test with a single salary
+ salary = new Salary("6000");
+ assertEquals("6000", salary.toString());
+ }
+
+ @Test
+ public void equals() {
+ Salary salary1 = new Salary("5000-6000");
+ Salary salary2 = new Salary("5000-6000");
+ Salary salary3 = new Salary("4000-5000");
+ Salary salary4 = new Salary("5000");
+
+ // same object -> returns true
+ assertTrue(salary1.equals(salary1));
+
+ // same values -> returns true
+ assertTrue(salary1.equals(salary2));
+
+ // different values -> returns false
+ assertFalse(salary1.equals(salary3));
+
+ // different type -> returns false
+ assertFalse(salary1.equals(5));
+
+ // null -> returns false
+ assertFalse(salary1.equals(null));
+
+ // different range status -> returns false
+ assertFalse(salary1.equals(salary4));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/UserTest.java b/src/test/java/seedu/address/model/person/UserTest.java
new file mode 100644
index 00000000000..1686b575bfb
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/UserTest.java
@@ -0,0 +1,35 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.person.user.User;
+
+public class UserTest {
+ private User user = User.getInstance();
+ @Test
+ public void nullCompanyName_isNull() {
+ assertEquals(null, user.getCompanyName());
+ }
+ @Test
+ public void nullName_isNull() {
+ assertEquals(null, user.getName());
+ }
+ @Test
+ public void nullSalary_isNull() {
+ assertEquals(null, user.getSalary());
+ }
+ @Test
+ public void nullEmail_isNull() {
+ assertEquals(null, user.getEmail());
+ }
+ @Test
+ public void nullPhone_isNull() {
+ assertEquals(null, user.getPhone());
+ }
+ @Test
+ public void nullEducation_isNull() {
+ assertEquals(null, user.getEducation());
+ }
+}
diff --git a/src/test/java/seedu/address/model/tag/TagContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/tag/TagContainsKeywordsPredicateTest.java
new file mode 100644
index 00000000000..ad783d69827
--- /dev/null
+++ b/src/test/java/seedu/address/model/tag/TagContainsKeywordsPredicateTest.java
@@ -0,0 +1,79 @@
+package seedu.address.model.tag;
+
+import static seedu.address.logic.parser.FilterTagCommandParser.createTags;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.testutil.PersonBuilder;
+
+public class TagContainsKeywordsPredicateTest {
+
+ @Test
+ public void equals() throws ParseException {
+ List firstPredicateKeywordList = createTags("first");
+ List secondPredicateKeywordList = createTags("first", "second");
+
+ TagContainsKeywordsPredicate firstPredicate = new TagContainsKeywordsPredicate(firstPredicateKeywordList);
+ TagContainsKeywordsPredicate secondPredicate = new TagContainsKeywordsPredicate(secondPredicateKeywordList);
+
+ // same object -> returns true
+ Assertions.assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ TagContainsKeywordsPredicate firstPredicateCopy = new TagContainsKeywordsPredicate(firstPredicateKeywordList);
+ Assertions.assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ Assertions.assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ Assertions.assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ Assertions.assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_tagContainsKeywords_returnsTrue() throws ParseException {
+ // One keyword
+ TagContainsKeywordsPredicate predicate = new TagContainsKeywordsPredicate(createTags("manager"));
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").withTags("manager").build()));
+
+ // Multiple keywords
+ predicate = new TagContainsKeywordsPredicate(createTags("manager", "HR"));
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").withTags("manager")
+ .build()));
+
+ // Only one matching keyword
+ predicate = new TagContainsKeywordsPredicate(createTags("manager", "HR"));
+ Assertions.assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").withTags("manager", "HR")
+ .build()));
+
+ }
+
+ @Test
+ public void test_tagDoesNotContainKeywords_returnsFalse() throws ParseException {
+ // Zero keywords
+ TagContainsKeywordsPredicate predicate = new TagContainsKeywordsPredicate(Collections.emptyList());
+ Assertions.assertFalse(predicate.test(new PersonBuilder().withName("Alice").withTags("manager").build()));
+
+ // Non-matching keyword
+ predicate = new TagContainsKeywordsPredicate(createTags("manager"));
+ Assertions.assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ }
+
+ @Test
+ public void toStringMethodOverride() {
+ List tags = Arrays.asList(new Tag("tag1"), new Tag("tag2"));
+ TagContainsKeywordsPredicate instance = new TagContainsKeywordsPredicate(tags);
+
+ String expected = "[tag1], [tag2]";
+ Assertions.assertEquals(expected, instance.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
index 83b11331cdb..39a2225f8b6 100644
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
@@ -13,97 +13,210 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
public class JsonAdaptedPersonTest {
+ private static final String INVALID_COMPANY_NAME = "123456789 123456789 123456789 123456789 123456789 123456789 "
+ + "123456789 123456789 123456789 123456789 1";
private static final String INVALID_NAME = "R@chel";
private static final String INVALID_PHONE = "+651234";
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
+ private static final String INVALID_SALARY = "dsadasdasd";
private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_INTERVIEWTIME = "04132022";
+ private static final String INVALID_PROGRAMMING_LANG = "-Java";
+ private static final String INVALID_PRIORITY = "5";
+ private static final String VALID_COMPANY_NAME = BENSON.getCompanyName().toString();
private static final String VALID_NAME = BENSON.getName().toString();
private static final String VALID_PHONE = BENSON.getPhone().toString();
private static final String VALID_EMAIL = BENSON.getEmail().toString();
private static final String VALID_ADDRESS = BENSON.getAddress().toString();
+ private static final String VALID_INTERVIEWTIME = BENSON.getDateTime().rawToString();
+ private static final String VALID_SALARY = BENSON.getSalary().toString();
+ private static final String VALID_INFO = BENSON.getInfo().toString();
private static final List VALID_TAGS = BENSON.getTags().stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList());
+ private static final List VALID_PROGRAMMING_LANG =
+ BENSON.getProgrammingLanguages().stream()
+ .map(JsonAdaptedProgrammingLanguage::new)
+ .collect(Collectors.toList());
+ private static final String VALID_PRIORITY = String.valueOf(BENSON.getPriority());
@Test
public void toModelType_validPersonDetails_returnsPerson() throws Exception {
JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON);
assertEquals(BENSON, person.toModelType());
}
-
+ @Test
+ public void toModelType_invalidCompanyName_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(INVALID_COMPANY_NAME, VALID_NAME,
+ VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
+ String expectedMessage = CompanyName.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+ @Test
+ public void toModelType_nullCompanyName_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(null, VALID_NAME,
+ VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, CompanyName.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
@Test
public void toModelType_invalidName_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_COMPANY_NAME, INVALID_NAME,
+ VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = Name.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(
+ VALID_COMPANY_NAME, null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, INVALID_PHONE, VALID_EMAIL,
+ VALID_ADDRESS, VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(
+ VALID_COMPANY_NAME, VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, INVALID_EMAIL,
+ VALID_ADDRESS, VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = Email.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(
+ VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, VALID_EMAIL,
+ INVALID_ADDRESS, VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = Address.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, VALID_EMAIL,
+ null, VALID_INTERVIEWTIME, VALID_SALARY, VALID_INFO,
+ VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
+ @Test
+ public void toModelType_invalidSalary_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(
+ VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ INVALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
+ String expectedMessage = Salary.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullSalary_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(
+ VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ null, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, VALID_PRIORITY);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Salary.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
@Test
public void toModelType_invalidTags_throwsIllegalValueException() {
List invalidTags = new ArrayList<>(VALID_TAGS);
invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
+ List invalidLanguages = new ArrayList<>(VALID_PROGRAMMING_LANG);
+ invalidLanguages.add(new JsonAdaptedProgrammingLanguage(INVALID_PROGRAMMING_LANG));
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE, VALID_EMAIL,
+ VALID_ADDRESS, null, VALID_SALARY, VALID_INFO, invalidTags, invalidLanguages, VALID_PRIORITY);
+ assertThrows(IllegalValueException.class, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_validPriority_success() throws Exception {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "1");
+ assertEquals(1, person.toModelType().getPriority());
+
+ person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "2");
+ assertEquals(2, person.toModelType().getPriority());
+
+ person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "3");
+ assertEquals(3, person.toModelType().getPriority());
+ }
+
+ @Test
+ public void toModelType_invalidPriority_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "-1");
+ assertThrows(IllegalValueException.class, person::toModelType);
+
+ person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "5");
+ assertThrows(IllegalValueException.class, person::toModelType);
+
+ person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, "abc");
+ assertThrows(IllegalValueException.class, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullPriority_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_COMPANY_NAME, VALID_NAME, VALID_PHONE,
+ VALID_EMAIL, VALID_ADDRESS, VALID_INTERVIEWTIME,
+ VALID_SALARY, VALID_INFO, VALID_TAGS, VALID_PROGRAMMING_LANG, null);
assertThrows(IllegalValueException.class, person::toModelType);
}
diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
index ed0a413526a..9392963b7d3 100644
--- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
@@ -73,7 +73,7 @@ public void readUserPrefs_extraValuesInFile_extraValuesIgnored() throws DataLoad
private UserPrefs getTypicalUserPrefs() {
UserPrefs userPrefs = new UserPrefs();
userPrefs.setGuiSettings(new GuiSettings(1000, 500, 300, 100));
- userPrefs.setAddressBookFilePath(Paths.get("addressbook.json"));
+ userPrefs.setAddressBookFilePath(Paths.get("ccbot.json"));
return userPrefs;
}
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
index 4584bd5044e..c9ea7db574d 100644
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
@@ -5,11 +5,16 @@
import java.util.stream.Stream;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
/**
@@ -32,11 +37,25 @@ public EditPersonDescriptorBuilder(EditPersonDescriptor descriptor) {
*/
public EditPersonDescriptorBuilder(Person person) {
descriptor = new EditPersonDescriptor();
+ descriptor.setCompanyName(person.getCompanyName());
descriptor.setName(person.getName());
descriptor.setPhone(person.getPhone());
descriptor.setEmail(person.getEmail());
descriptor.setAddress(person.getAddress());
+ descriptor.setDateTime(person.getDateTime());
descriptor.setTags(person.getTags());
+ descriptor.setProgrammingLanguages(person.getProgrammingLanguages());
+ descriptor.setSalary(person.getSalary());
+ descriptor.setInfo(person.getInfo());
+ descriptor.setPriority(person.getPriority());
+ }
+
+ /**
+ * Sets the {@code CompanyName} of the {@code Person} that we are building.
+ */
+ public EditPersonDescriptorBuilder withCompanyName(String name) {
+ descriptor.setCompanyName(new CompanyName(name));
+ return this;
}
/**
@@ -71,6 +90,31 @@ public EditPersonDescriptorBuilder withAddress(String address) {
return this;
}
+ /**
+ * To add interview-time to the person object
+ * @param dateTime input
+ * @return the object
+ */
+ public EditPersonDescriptorBuilder withInterviewTime(String dateTime) {
+ descriptor.setDateTime(new InterviewTime(dateTime));
+ return this;
+ }
+ /**
+ * Sets the {@code Salary} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withSalary(String salary) {
+ descriptor.setSalary(new Salary(salary));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Info} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withInfo(String info) {
+ descriptor.setInfo(new Info(info));
+ return this;
+ }
+
/**
* Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor}
* that we are building.
@@ -81,7 +125,29 @@ public EditPersonDescriptorBuilder withTags(String... tags) {
return this;
}
+ /**
+ * Parses the {@code programmingLanguages} into a {@code Set} and
+ * sets it to the {@code EditPersonDescriptorBuilder}.
+ * @param programmingLanguages The programming languages to be set.
+ * @return The updated {@code EditPersonDescriptorBuilder} object.
+ */
+ public EditPersonDescriptorBuilder withProgrammingLanguages(String... programmingLanguages) {
+ Set programmingLanguageSet = Stream.of(programmingLanguages).map(ProgrammingLanguage::new)
+ .collect(Collectors.toSet());
+ descriptor.setProgrammingLanguages(programmingLanguageSet);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Priority} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withPriority(String priority) {
+ descriptor.setPriority(Integer.parseInt(priority));
+ return this;
+ }
+
public EditPersonDescriptor build() {
return descriptor;
}
+
}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
index 6be381d39ba..70109067fee 100644
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ b/src/test/java/seedu/address/testutil/PersonBuilder.java
@@ -3,11 +3,16 @@
import java.util.HashSet;
import java.util.Set;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Address;
+import seedu.address.model.person.CompanyName;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Info;
+import seedu.address.model.person.InterviewTime;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.Salary;
import seedu.address.model.tag.Tag;
import seedu.address.model.util.SampleDataUtil;
@@ -15,38 +20,67 @@
* A utility class to help with building Person objects.
*/
public class PersonBuilder {
-
+ public static final String DEFAULT_COMPANY_NAME = "Google";
public static final String DEFAULT_NAME = "Amy Bee";
public static final String DEFAULT_PHONE = "85355255";
public static final String DEFAULT_EMAIL = "amy@gmail.com";
public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
+ public static final String DEFAULT_INTERVIEWTIME = "121220221400";
+ public static final String DEFAULT_SALARY = "0";
+ public static final String DEFAULT_INFO = "";
+ public static final int DEFAULT_PRIORITY = 2;
+ private CompanyName companyName;
private Name name;
private Phone phone;
private Email email;
private Address address;
+ private InterviewTime dateTime;
+ private Salary salary;
+ private Info info;
private Set tags;
-
+ private Set programmingLanguages;
+ private int priority;
/**
* Creates a {@code PersonBuilder} with the default details.
*/
public PersonBuilder() {
+ companyName = new CompanyName(DEFAULT_COMPANY_NAME);
name = new Name(DEFAULT_NAME);
phone = new Phone(DEFAULT_PHONE);
email = new Email(DEFAULT_EMAIL);
address = new Address(DEFAULT_ADDRESS);
+ dateTime = new InterviewTime(DEFAULT_INTERVIEWTIME);
+ salary = new Salary(DEFAULT_SALARY);
+ info = new Info(DEFAULT_INFO);
tags = new HashSet<>();
+ programmingLanguages = new HashSet<>();
+ priority = DEFAULT_PRIORITY;
}
/**
* Initializes the PersonBuilder with the data of {@code personToCopy}.
*/
public PersonBuilder(Person personToCopy) {
+ companyName = personToCopy.getCompanyName();
name = personToCopy.getName();
phone = personToCopy.getPhone();
email = personToCopy.getEmail();
address = personToCopy.getAddress();
+ dateTime = personToCopy.getDateTime();
+ salary = personToCopy.getSalary();
+ info = personToCopy.getInfo();
tags = new HashSet<>(personToCopy.getTags());
+ programmingLanguages = new HashSet<>(personToCopy.getProgrammingLanguages());
+ priority = personToCopy.getPriority();
+ }
+
+ /**
+ * Sets the {@code CompanyName} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withCompanyName(String name) {
+ this.companyName = new CompanyName(name);
+ return this;
}
/**
@@ -60,7 +94,7 @@ public PersonBuilder withName(String name) {
/**
* Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building.
*/
- public PersonBuilder withTags(String ... tags) {
+ public PersonBuilder withTags(String... tags) {
this.tags = SampleDataUtil.getTagSet(tags);
return this;
}
@@ -73,6 +107,22 @@ public PersonBuilder withAddress(String address) {
return this;
}
+ /**
+ * Sets the {@code Salary} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withSalary(String salary) {
+ this.salary = new Salary(salary);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Info} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withInfo(String info) {
+ this.info = new Info(info);
+ return this;
+ }
+
/**
* Sets the {@code Phone} of the {@code Person} that we are building.
*/
@@ -89,8 +139,42 @@ public PersonBuilder withEmail(String email) {
return this;
}
+ /**
+ * Adds dateTime to PersonBuilder object
+ * @param dateTime input
+ * @return object
+ */
+ public PersonBuilder withDateTime(String dateTime) {
+ this.dateTime = new InterviewTime(dateTime);
+ return this;
+ }
+
+ /**
+ * Parses the {@code programmingLanguages} into a {@code Set} and
+ * sets it to the {@code Person} that we are building.
+ * @param programmingLanguages The programming languages to be set.
+ * @return The updated {@code PersonBuilder} object.
+ */
+ public PersonBuilder withProgrammingLanguages(String... programmingLanguages) {
+ this.programmingLanguages = SampleDataUtil.getProgrammingLanguageSet(programmingLanguages);
+ return this;
+ }
+
+ /**
+ * Sets the {@code priority} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withPriority(int priority) {
+ this.priority = priority;
+ return this;
+ }
+
+ /**
+ * Builds and returns a {@code Person} object with the current attributes set in this {@code PersonBuilder}.
+ * @return The {@code Person} object constructed with the current attributes set in this builder.
+ */
public Person build() {
- return new Person(name, phone, email, address, tags);
+ return new Person(companyName, name, phone, email, address, dateTime, salary, info, tags,
+ programmingLanguages, priority);
}
}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java
index 90849945183..334320b5636 100644
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ b/src/test/java/seedu/address/testutil/PersonUtil.java
@@ -1,18 +1,27 @@
package seedu.address.testutil;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import java.time.format.DateTimeFormatter;
import java.util.Set;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.person.Person;
import seedu.address.model.tag.Tag;
+
/**
* A utility class for Person.
*/
@@ -29,14 +38,20 @@ public static String getAddCommand(Person person) {
* Returns the part of command string for the given {@code person}'s details.
*/
public static String getPersonDetails(Person person) {
+ DateTimeFormatter reformat = DateTimeFormatter.ofPattern("ddMMyyyyHHmm");
StringBuilder sb = new StringBuilder();
+ sb.append(PREFIX_COMPANY_NAME + person.getCompanyName().companyName + " ");
sb.append(PREFIX_NAME + person.getName().fullName + " ");
sb.append(PREFIX_PHONE + person.getPhone().value + " ");
sb.append(PREFIX_EMAIL + person.getEmail().value + " ");
sb.append(PREFIX_ADDRESS + person.getAddress().value + " ");
+ sb.append(PREFIX_INTERVIEWTIME + person.getDateTime().dateTime.format(reformat) + " ");
person.getTags().stream().forEach(
s -> sb.append(PREFIX_TAG + s.tagName + " ")
);
+ person.getProgrammingLanguages().stream().forEach(
+ pl -> sb.append(PREFIX_PROGRAMMING_LANGUAGE + pl.languageName + " ")
+ );
return sb.toString();
}
@@ -44,11 +59,19 @@ public static String getPersonDetails(Person person) {
* Returns the part of command string for the given {@code EditPersonDescriptor}'s details.
*/
public static String getEditPersonDescriptorDetails(EditPersonDescriptor descriptor) {
+ DateTimeFormatter reformat = DateTimeFormatter.ofPattern("ddMMyyyyHHmm");
StringBuilder sb = new StringBuilder();
+ descriptor.getCompanyName().ifPresent(companyName -> sb.append(PREFIX_COMPANY_NAME)
+ .append(companyName.companyName).append(" "));
descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
+ descriptor.getPriority().ifPresent(Integer -> sb.append(PREFIX_PRIORITY).append(Integer).append(" "));
+ descriptor.getInfo().ifPresent(info -> sb.append(PREFIX_INFO).append(info.value).append(" "));
+ descriptor.getSalary().ifPresent(salary -> sb.append(PREFIX_SALARY).append(salary.toString()).append(" "));
+ descriptor.getDateTime().ifPresent(dateTime ->
+ sb.append(PREFIX_INTERVIEWTIME).append(dateTime.dateTime.format(reformat)).append(" "));
if (descriptor.getTags().isPresent()) {
Set tags = descriptor.getTags().get();
if (tags.isEmpty()) {
@@ -57,6 +80,16 @@ public static String getEditPersonDescriptorDetails(EditPersonDescriptor descrip
tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" "));
}
}
+ sb.append(" ");
+ if (descriptor.getProgrammingLanguages().isPresent()) {
+ Set programmingLanguages = descriptor.getProgrammingLanguages().get();
+ if (programmingLanguages.isEmpty()) {
+ sb.append(PREFIX_PROGRAMMING_LANGUAGE);
+ } else {
+ programmingLanguages.forEach(s -> sb.append(PREFIX_PROGRAMMING_LANGUAGE)
+ .append(s.languageName).append(" "));
+ }
+ }
return sb.toString();
}
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
index fec76fb7129..2a6aa7480ad 100644
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ b/src/test/java/seedu/address/testutil/TypicalPersons.java
@@ -2,8 +2,12 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_COMPANY_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_COMPANY_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INTERVIEWTIME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_INTERVIEWTIME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
@@ -23,24 +27,58 @@
*/
public class TypicalPersons {
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
+ public static final Person ALICE = new PersonBuilder().withCompanyName("Google").withName("Alice Pauline")
.withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
.withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
+ .withTags("friends")
+ .withProgrammingLanguages("Java")
+ .withSalary("200000")
+ .withPriority(2)
+ .build();
+ public static final Person BENSON = new PersonBuilder().withCompanyName("Amazon").withName("Benson Meier")
.withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
+ .withEmail("johnd@example.com")
+ .withPhone("98765432")
+ .withTags("owesMoney", "friends")
+ .withDateTime("121220221500")
+ .withSalary("1000")
+ .withProgrammingLanguages("Java")
+ .withPriority(1)
+ .build();
+
+ public static final Person CARL = new PersonBuilder().withCompanyName("Shopee").withName("Carl Kurz")
+ .withPhone("95352563")
+ .withEmail("heinz@example.com")
+ .withAddress("wall street")
+ .withProgrammingLanguages("Java")
+ .withPriority(3)
+ .build();
+ public static final Person DANIEL = new PersonBuilder().withCompanyName("Tiktok").withName("Daniel Meier")
+ .withPhone("87652533")
+ .withEmail("cornelia@example.com")
+ .withAddress("10th street")
+ .withTags("friends")
+ .withProgrammingLanguages("Java")
+ .withPriority(2)
+ .build();
+ public static final Person ELLE = new PersonBuilder().withCompanyName("Shopback").withName("Elle Meyer")
+ .withPhone("9482224")
+ .withEmail("werner@example.com")
+ .withAddress("michegan ave")
+ .withPriority(2)
+ .build();
+ public static final Person FIONA = new PersonBuilder().withCompanyName("Apple").withName("Fiona Kunz")
+ .withPhone("9482427")
+ .withEmail("lydia@example.com")
+ .withAddress("little tokyo")
+ .withPriority(1)
+ .build();
+ public static final Person GEORGE = new PersonBuilder().withCompanyName("Microsoft").withName("George Best")
+ .withPhone("9482442")
+ .withEmail("anna@example.com")
+ .withAddress("4th street")
+ .withPriority(3)
+ .build();
// Manually added
public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
@@ -49,11 +87,14 @@ public class TypicalPersons {
.withEmail("hans@example.com").withAddress("chicago ave").build();
// Manually added - Person's details found in {@code CommandTestUtil}
- public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
- public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
- .build();
+ public static final Person AMY = new PersonBuilder().withCompanyName(VALID_COMPANY_NAME_AMY)
+ .withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY)
+ .withAddress(VALID_ADDRESS_AMY).withDateTime(VALID_INTERVIEWTIME_AMY).withTags(VALID_TAG_FRIEND)
+ .withProgrammingLanguages("Java").build();
+ public static final Person BOB = new PersonBuilder().withCompanyName(VALID_COMPANY_NAME_BOB)
+ .withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
+ .withAddress(VALID_ADDRESS_BOB).withDateTime(VALID_INTERVIEWTIME_BOB)
+ .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).withProgrammingLanguages("Java").build();
public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER