...>...`
+
+* `find [t]` **is required** to start with a `g/` flag.
+* Finding tasks `[t]` **only** accepts `g/`,`h/`, `d/`, `t/`, and `i/` flags.
+* If a SEARCH_TERM without a flag (e.g. `find [t] g/update`) is used, an error will be raised.
+* SEARCH_TERMs are still required to follow the format as defined as by their respective flags.
+
+:bulb: View constraints on flags and parameters [here](#flags-and-parameters-format-constraints)
+
+Examples:
+`find [t] g/d/2022-03-04 g/h/Update interview list g/t/10:10` is logically equivalent to
+`find [t] d/2022-03-04 OR h/Update interview list OR t/10:10`
+
+
+
+`find [t] g/d/2022-03-06 h/Update interview list t/09:00` is logically equivalent to
+`find [t] d/2022-03-06 AND h/Update interview list AND t/09:00`
+
+`find [t] g/d/2022-03-06 h/Update interview list g/t/10:10` is logically equivalent to
+`find [t] (d/2022-03-06 AND h/Update interview list) OR t/10:10`
+
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+
+## Storage
+----------
+### Saving the data
+HRConnect data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+
+
### Editing the data file
+HRConnect data are saved as a JSON file `PATH_TO_JAR_FILE/data/HRConnect.json`. Advanced users are welcome to update data directly by editing that data file.
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+:exclamation: **Caution:** If your changes to the data file makes its format invalid, the HRConnect will discard all data and start with an empty data file at the next run.
+:exclamation: **Caution:** Manual modification of the JSON file is **NOT** a supported feature. Inconsistent data resulting from manual modification of the data file should **NOT** be considered as unexpected behaviour.
+Example: Manually editing the `NAME` of applicant in the applicant list of the data file but not on interview list will lead to inconsistent data vice versa and any unusual behaviour caused by this should **NOT** be seen as a bug.
-: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.
-
+
+
+
+### Importing the data file: `import`
+
+Imports all **job applicants** data from a *csv* save file generated from this HRConnect.
+
+File structure for csv file (tab delimited):
+
+name | phone number | email | address | job position | stage
+
+Notes:
+1. Filepath can be relative or absolute.
+2. No duplicates are allowed to be imported into the HRConnect.
+ 1. Data in the HRConnect has a higher priority than data in the save file.
+3. Save files needs to end with `.csv` in order for the HRConnect to recognise the save file.
+4. The csv save file can have at most 1 newline at the end of file for it to be considered valid.
+5. If any error is found, **none** of the data in the save file will be imported into the HRConnect.
+
+Format: `import FILEPATH`
+
+Example:
+`import C:\Users\YOUR_USERNAME\Desktop\data.csv`
+
+
+
+
+### Exporting to a csv data file: `export`
+
+Exports all **job applicants** data from the HRConnect into a *csv* save file.
+
+File structure for csv file (tab delimited):
+
+name | phone number | email | address | job position | stage
+
+Notes:
+1. Filepath of specified CSV file can be relative or absolute.
+2. Specifying the same csv file name and path will overwrite the data inside the specified csv file.
+3. Csv file **must** have .csv as a file extension.
+4. If any error is found while executing the command,
+**none** of the data from the HRConnect will be exported into the specified csv file.
+
+:exclamation: **Important:** Some invalid naming conventions for the specified csv file might be allowed
+on different OS. E.g. `my:Data.csv` is a valid name on MacOS but not on WindowsOS.
+
+Format: `export FILEPATH`
+
+Absolute filepath example for WindowsOS: `export C:\Users\YOUR_USERNAME\Desktop\myData.csv`
+Relative filepath example for WindowsOS: `export .\myData.csv`
+Absolute filepath example for MacOS: `export /Users/YOUR_USERNAME/Downloads/myDataFile.csv`
+Relative filepath example for MacOS: `export ./myDataFile.csv`
+
+:exclamation: **Important:** Some file paths might be recognised as valid/invalid depending on the OS.
+
+:exclamation: **Important:** Data in exported csv file will look different depending on the application used to view the
+file even though the data is seperated by tabs.
+
+
+
+# Summary
+## Flags and Parameters Format Constraints
+
+| Flags | Parameters | Format Constraints |
+|------:|--------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| a/ | ADDRESS | Addresses can take any values, and it should not be blank |
+| d/ | DATE | Date should be in the format YYYY-MM-dd |
+| e/ | EMAIL | Emails should be of the format local-part@domain and adhere to the following constraints: 1. The local-part should only contain alphanumeric characters and these special characters, excluding the parentheses, (+_.-). The local-part may not start or end with any special characters. 2. This is followed by a '@' and then a domain name. The domain name is made up of domain labels separated by periods. The domain name must: - end with a domain label at least 2 characters long - have each domain label start and end with alphanumeric characters - have each domain label consist of alphanumeric characters, separated only by hyphens, if any. |
+| g/ | SEARCH_TERM | Only used in the `find` command. Used in combination with the other flags on this list. |
+| h/ | HEADER | Header should only contain alphanumeric characters and spaces, and it should not be blank |
+| i/ | INFORMATION | Information should only contain alphanumeric characters and spaces, and it should not be blank |
+| j/ | JOB_POSITION | Job should only contain alphanumeric characters and spaces, and it should not be blank |
+| n/ | NAME | Names should only contain alphanumeric characters and spaces, and it should not be blank |
+| p/ | PHONE_NUMBER | Phone numbers should only contain numbers, and it should be at least 3 digits long |
+| s/ | STAGE | Stage should be only INPROGRESS or ACCEPTED or REJECTED (case-sensitive) |
+| t/ | TIME | Time should be in the format HH:MM |
+
+
+## Section Types
+
+| Type | Format |
+|-----:|:--------------------------------------------------|
+| [i] | Applies the current command to the interview list |
+| [p] | Applies the current command to the applicant list |
+| [t] | Applies the current command to the task list |
+
+
+
+## Command Summary
+
+**General Command Summary**
+
+| Action | Format |
+|:------:|:------:|
+| Help | `help` |
+| Exit | `exit` |
+
+
+
+**Applicant Command Summary**
+
+| Action | Format |
+|----------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Add Job Applicant | `add [p] n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS j/JOB_POSITION s/STAGE` |
+| Edit Job Applicant | `edit [p] INDEX ` (`INDEX` refers to numerical position of applicant in applicant list) |
+| Delete Job Applicant | `delete [p] INDEX` (`INDEX` refers to numerical position of applicant in applicant list) |
+| List Job Applicants | `list [p]` |
+| Clear Job Applicants | `clear [p]` |
+| Find Job Applicant(s) | `find [p] g/SEARCH_TERM ... ...>...` |
+
+
-### Archiving data files `[coming in v2.0]`
+**Interview Command Summary**
-_Details coming soon ..._
+| Action | Format |
+|------------------:|:---------------------------------------------------------------------------------------------------------|
+| Add Interview | `add [i] INDEX d/DATE t/TIME` (`INDEX` refers to numerical position of applicant in applicant list) |
+| Edit Interview | `edit [i] INDEX ` (`INDEX` refers to numerical position of interview in interview list) |
+| Delete Interview | `delete [i] INDEX` (`INDEX` refers to numerical position of interview in interview list) |
+| List Interviews | `list [i]` |
+| Clear Interviews | `clear [i]` |
+| Find Interview(s) | `find [i] g/SEARCH_TERM ... ...>...` |
---------------------------------------------------------------------------------------------------------------------
+
-## FAQ
+**Task Command Summary**
-**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.
+| Action | Format |
+|-------------:|:--------------------------------------------------------------------------------------------------------------------------|
+| Add Task | `add [t] h/HEADER d/DATE t/TIME i/INFORMATION` |
+| Edit Task | `edit [t] INDEX ` (`INDEX` refers to numerical position of task in task list) |
+| Delete Task | `delete [t] INDEX` (`INDEX` refers to numerical position of task in task list) |
+| List Tasks | `list [t]` |
+| Clear Tasks | `clear [t]` |
+| Find Task(s) | `find [t] g/SEARCH_TERM ... ...>...` |
---------------------------------------------------------------------------------------------------------------------
+
-## Command summary
+**Storage 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 |
+|:--------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
+| Import | `import FILEPATH` |
+| Export | `export FILEPATH` |
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..fd150f8f8e0 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,5 +1,5 @@
-title: "AB-3"
-theme: minima
+title: "HRConnect"
+theme: jekyll-theme-architect
header_pages:
- UserGuide.md
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2122S2-CS2103T-W11-2/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..9e97abbce38 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: "HRConnect";
font-size: 32px;
}
}
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..d5a5f0b8a2a 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -7,10 +7,10 @@ Participant ":Logic" as logic LOGIC_COLOR
Participant ":Model" as model MODEL_COLOR
Participant ":Storage" as storage STORAGE_COLOR
-user -[USER_COLOR]> ui : "delete 1"
+user -[USER_COLOR]> ui : "delete [p] 1"
activate ui UI_COLOR
-ui -[UI_COLOR]> logic : execute("delete 1")
+ui -[UI_COLOR]> logic : execute("delete [p] 1")
activate logic LOGIC_COLOR
logic -[LOGIC_COLOR]> model : deletePerson(p)
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 5731f9cbaa1..653471e0ece 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,33 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
+AddressBook *-right-> "1" UniqueInterviewList
AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
+AddressBook *-right-> "1" UniqueTaskList
+UniquePersonList -[hidden]down- UniqueInterviewList
+UniquePersonList -[hidden]down- UniqueInterviewList
+UniqueInterviewList -[hidden]down- UniqueTaskList
-UniqueTagList *-right-> "*" Tag
-UniquePersonList -right-> Person
+UniquePersonList -right-> "*" Person
+UniqueInterviewList -right-> "*"Interview
+UniqueTaskList -down-> "*"Task
-Person -up-> "*" Tag
+Person *-down-> Name
+Person *-down-> Phone
+Person *-down-> Email
+Person *-down-> Address
+Person *-down-> Job
+Person *-right-> Stage
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
+
+
+Interview *-up-> Person
+
+Interview *--> Date
+Interview *--> Time
+
+Task *--> Header
+Task *--> Information
+Task *--> Date
+Task *--> Time
@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..0cbc34f972f 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -5,7 +5,8 @@ box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
+participant ":DeletePersonCommandParser" as DeletePersonCommandParser LOGIC_COLOR
+participant "d:DeletePersonCommand" as DeletePersonCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
end box
@@ -13,10 +14,10 @@ box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("delete [p] 1")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
+LogicManager -> AddressBookParser : parseCommand("delete [p] 1")
activate AddressBookParser
create DeleteCommandParser
@@ -26,15 +27,23 @@ activate DeleteCommandParser
DeleteCommandParser --> AddressBookParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+AddressBookParser -> DeleteCommandParser : parse("[p] 1")
activate DeleteCommandParser
-create DeleteCommand
-DeleteCommandParser -> DeleteCommand
-activate DeleteCommand
+create DeletePersonCommandParser
+DeleteCommandParser -> DeletePersonCommandParser
+activate DeletePersonCommandParser
-DeleteCommand --> DeleteCommandParser : d
-deactivate DeleteCommand
+create DeletePersonCommand
+DeletePersonCommandParser -> DeletePersonCommand : parse("1")
+activate DeletePersonCommand
+
+
+DeletePersonCommand -> DeletePersonCommandParser : d
+deactivate DeletePersonCommand
+
+DeletePersonCommandParser --> DeleteCommandParser : d
+deactivate DeletePersonCommandParser
DeleteCommandParser --> AddressBookParser : d
deactivate DeleteCommandParser
@@ -45,24 +54,24 @@ destroy DeleteCommandParser
AddressBookParser --> LogicManager : d
deactivate AddressBookParser
-LogicManager -> DeleteCommand : execute()
-activate DeleteCommand
+LogicManager -> DeletePersonCommand : execute(model)
+activate DeletePersonCommand
-DeleteCommand -> Model : deletePerson(1)
+DeletePersonCommand -> Model : deletePerson(1)
activate Model
-Model --> DeleteCommand
+Model --> DeletePersonCommand
deactivate Model
create CommandResult
-DeleteCommand -> CommandResult
+DeletePersonCommand -> CommandResult
activate CommandResult
-CommandResult --> DeleteCommand
+CommandResult --> DeletePersonCommand
deactivate CommandResult
-DeleteCommand --> LogicManager : result
-deactivate DeleteCommand
+DeletePersonCommand --> LogicManager : result
+deactivate DeletePersonCommand
[<--LogicManager
deactivate LogicManager
diff --git a/docs/diagrams/ExportSequenceDiagram.puml b/docs/diagrams/ExportSequenceDiagram.puml
new file mode 100644
index 00000000000..7e177aac5da
--- /dev/null
+++ b/docs/diagrams/ExportSequenceDiagram.puml
@@ -0,0 +1,73 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":ExportCommandParser" as ExportCommandParser LOGIC_COLOR
+participant "e:ExportCommand" as ExportCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+box File Operations STORAGE_COLOR_T1
+participant ":PrintWriter" as PrintWriter MODEL_COLOR
+end box
+
+[-> ExportCommandParser : parse("../mydata.csv")
+activate ExportCommandParser
+
+
+ExportCommandParser -> ExportCommandParser : checkFilePath("../mydata.csv")
+activate ExportCommandParser
+
+ExportCommandParser --> ExportCommandParser
+deactivate ExportCommandParser
+
+create ExportCommand
+ExportCommandParser -> ExportCommand
+activate ExportCommand
+
+ExportCommand --> ExportCommandParser : e
+deactivate ExportCommand
+
+[<-- ExportCommandParser : e
+deactivate ExportCommandParser
+
+[<-[hidden]- ExportCommandParser
+destroy ExportCommandParser
+
+[-> ExportCommand : execute()
+activate ExportCommand
+
+create PrintWriter
+ExportCommand -> PrintWriter
+activate PrintWriter
+PrintWriter --> ExportCommand
+deactivate PrintWriter
+
+ExportCommand -> Model : getFilteredPersonList()
+activate Model
+Model --> ExportCommand : filteredPersonsList
+deactivate Model
+
+loop until end of filteredPersonsList
+ExportCommand -> PrintWriter : printf(person)
+activate PrintWriter
+PrintWriter --> ExportCommand
+deactivate PrintWriter
+end loop
+
+create CommandResult
+ExportCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ExportCommand
+deactivate CommandResult
+
+[<-- ExportCommand : result
+deactivate ExportCommand
+@enduml
+
+
diff --git a/docs/diagrams/FindCommandSequenceDiagram.puml b/docs/diagrams/FindCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..8bf4d98d7b1
--- /dev/null
+++ b/docs/diagrams/FindCommandSequenceDiagram.puml
@@ -0,0 +1,77 @@
+@startuml
+!include style.puml
+
+
+box Logic LOGIC_COLOR_T1
+participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR
+participant ":FindTaskCommandParser" as FindTaskCommandParser LOGIC_COLOR
+participant "t:FindTaskCommand" as FindTaskCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+participant ":TaskContainsKeywordsPredicate" as TaskContainsKeywordsPredicate MODEL_COLOR
+end box
+
+[-> FindCommandParser : parse("[t] g/i/update")
+activate FindCommandParser
+
+FindCommandParser -> FindCommandParser : checkValidGroups(["i/update"])
+activate FindCommandParser
+FindCommandParser --> FindCommandParser
+deactivate FindCommandParser
+
+create FindTaskCommandParser
+FindCommandParser -> FindTaskCommandParser
+activate FindTaskCommandParser
+FindTaskCommandParser --> FindCommandParser
+deactivate FindTaskCommandParser
+
+FindCommandParser -> FindTaskCommandParser : parse(["i/update"])
+activate FindTaskCommandParser
+
+FindTaskCommandParser -> FindCommandParser : checkInvalidInformation(["i/update"])
+FindCommandParser --> FindTaskCommandParser
+
+create TaskContainsKeywordsPredicate
+FindTaskCommandParser -> TaskContainsKeywordsPredicate
+activate TaskContainsKeywordsPredicate
+TaskContainsKeywordsPredicate --> FindTaskCommandParser
+deactivate TaskContainsKeywordsPredicate
+
+create FindTaskCommand
+FindTaskCommandParser -> FindTaskCommand
+activate FindTaskCommand
+FindTaskCommand --> FindTaskCommandParser : t
+deactivate FindTaskCommand
+
+FindTaskCommandParser --> FindCommandParser : t
+deactivate FindTaskCommandParser
+[<-[hidden]- FindTaskCommandParser
+destroy FindTaskCommandParser
+
+[<-- FindCommandParser : t
+deactivate FindCommandParser
+
+[<-[hidden]- FindCommandParser
+destroy FindCommandParser
+
+[-> FindTaskCommand : execute()
+activate FindTaskCommand
+
+FindTaskCommand -> Model : updateFilteredTaskList()
+activate Model
+Model --> FindTaskCommand
+deactivate Model
+
+create CommandResult
+FindTaskCommand -> CommandResult
+activate CommandResult
+CommandResult --> FindTaskCommand
+deactivate CommandResult
+
+[<-- FindTaskCommand : result
+deactivate FindTaskCommand
+
+@enduml
diff --git a/docs/diagrams/ImportCheckSequenceDiagram.puml b/docs/diagrams/ImportCheckSequenceDiagram.puml
new file mode 100644
index 00000000000..7a35c811d91
--- /dev/null
+++ b/docs/diagrams/ImportCheckSequenceDiagram.puml
@@ -0,0 +1,47 @@
+@startuml
+!include style.puml
+
+mainframe **sd** perform necessary checks
+
+box Logic LOGIC_COLOR_T1
+participant ":ImportCommandParser" as ImportCommandParser LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Person" as Person MODEL_COLOR
+end box
+
+activate ImportCommandParser
+
+
+loop until last entry is parsed
+ImportCommandParser -> ImportCommandParser : getFields(entry)
+activate ImportCommandParser
+ImportCommandParser --> ImportCommandParser
+deactivate ImportCommandParser
+
+ImportCommandParser -> ImportCommandParser : createPerson(entry)
+activate ImportCommandParser
+
+create Person
+ImportCommandParser -> Person
+activate Person
+Person --> ImportCommandParser
+deactivate Person
+
+
+
+
+
+
+ImportCommandParser --> ImportCommandParser
+deactivate ImportCommandParser
+
+ImportCommandParser -> ImportCommandParser : updatePersons(person)
+activate ImportCommandParser
+ImportCommandParser --> ImportCommandParser
+deactivate ImportCommandParser
+
+end
+
+@enduml
diff --git a/docs/diagrams/ImportSequenceDiagram.puml b/docs/diagrams/ImportSequenceDiagram.puml
new file mode 100644
index 00000000000..fdd26796820
--- /dev/null
+++ b/docs/diagrams/ImportSequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":ImportCommandParser" as ImportCommandParser LOGIC_COLOR
+participant "i:ImportCommand" as ImportCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> ImportCommandParser : parse("../mydata.csv")
+activate ImportCommandParser
+
+ImportCommandParser -> ImportCommandParser : checkFilePath("../mydata.csv")
+activate ImportCommandParser
+ImportCommandParser --> ImportCommandParser
+deactivate ImportCommandParser
+
+ImportCommandParser -> ImportCommandParser : readCsv("../mydata.csv")
+activate ImportCommandParser
+
+ref over ImportCommandParser
+perform necessary checks
+end ref
+
+ImportCommandParser --> ImportCommandParser
+deactivate ImportCommandParser
+
+create ImportCommand
+ImportCommandParser -> ImportCommand
+activate ImportCommand
+
+ImportCommand --> ImportCommandParser : i
+deactivate ImportCommand
+
+[<-- ImportCommandParser : i
+deactivate ImportCommandParser
+
+[<-[hidden]- ImportCommandParser : e
+destroy ImportCommandParser
+
+[-> ImportCommand : execute()
+activate ImportCommand
+
+loop until end of persons list
+ImportCommand -> Model : hasPerson(person)
+activate Model
+Model --> ImportCommand
+deactivate Model
+end
+
+loop until end of persons list
+ImportCommand -> Model : addPerson(person)
+activate Model
+Model --> ImportCommand
+deactivate Model
+end
+
+
+create CommandResult
+ImportCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ImportCommand
+deactivate CommandResult
+
+[<-- ImportCommand : result
+deactivate ImportCommand
+
+@enduml
+
+
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index d4193173e18..4a4c5263531 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -8,9 +8,10 @@ package Logic {
Class AddressBookParser
Class XYZCommand
+Class "{abstract}\nXYZCommand" as XYZAbstractCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
-
+Class XYZTYPECommand
Class "<>\nLogic" as Logic
Class LogicManager
@@ -29,16 +30,21 @@ HiddenOutside ..> Logic
LogicManager .right.|> Logic
LogicManager -right->"1" AddressBookParser
AddressBookParser ..> XYZCommand : creates >
+AddressBookParser ..> XYZTYPECommand : creates >
-XYZCommand -up-|> Command
-LogicManager .left.> Command : executes >
+XYZAbstractCommand -up-|> Command
+XYZCommand -left-|> Command
+LogicManager ..> Command : executes >
+XYZTYPECommand -up-|> XYZAbstractCommand
LogicManager --> Model
LogicManager --> Storage
Storage --[hidden] Model
Command .[hidden]up.> Storage
Command .right.> Model
-note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc
+note right of XYZAbstractCommand: e.g. AddCommand, \nFindCommand
+note right of XYZCommand: e.g. HelpCommand, \nExitCommand
+note right of XYZTYPECommand: e.g. AddPersonCommand, \n FindTaskCommand
Logic ..> CommandResult
LogicManager .down.> CommandResult
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..66d667faf5b 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -14,12 +14,12 @@ Class UserPrefs
Class UniquePersonList
Class Person
-Class Address
-Class Email
-Class Name
-Class Phone
-Class Tag
+Class UniqueInterviewList
+Class Interview
+
+Class UniqueTaskList
+Class Task
}
Class HiddenOutside #FFFFFF
@@ -30,21 +30,18 @@ AddressBook .up.|> ReadOnlyAddressBook
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+ModelManager --> "1" AddressBook
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
AddressBook *--> "1" UniquePersonList
+AddressBook *--> "1" UniqueInterviewList
+AddressBook *--> "1" UniqueTaskList
UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
-
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+UniqueInterviewList --> "~* all" Interview
+UniqueTaskList --> "~* all" Task
ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" Interview
+ModelManager -->"~* filtered" Task
@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 0c7424de6e0..a2598d2c228 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -4,11 +4,11 @@ skinparam arrowThickness 1.1
skinparam arrowColor LOGIC_COLOR_T4
skinparam classBackgroundColor LOGIC_COLOR
-Class "{abstract}\nCommand" as Command
-Class XYZCommand
package "Parser classes"{
Class "<>\nParser" as Parser
+Class "{abstract}\nCommand" as Command
+Class "{abstract}\nXYZCommand" as XYZAbstractCommand
Class AddressBookParser
Class XYZCommandParser
Class CliSyntax
@@ -16,23 +16,36 @@ Class ParserUtil
Class ArgumentMultimap
Class ArgumentTokenizer
Class Prefix
+Class XYZTYPECommandParser
+Class XYZTYPECommand
+Class XYZCommand
+enum Type
}
Class HiddenOutside #FFFFFF
HiddenOutside ..> AddressBookParser
AddressBookParser .down.> XYZCommandParser: creates >
-
-XYZCommandParser ..> XYZCommand : creates >
AddressBookParser ..> Command : returns >
+XYZCommandParser ..> XYZTYPECommand : creates >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
-ArgumentTokenizer .left.> ArgumentMultimap
XYZCommandParser ..> CliSyntax
+XYZCommandParser ..> XYZCommand : creates >
+XYZCommandParser ..> XYZAbstractCommand : returns >
+XYZTYPECommandParser ..> XYZTYPECommand : creates >
+XYZTYPECommandParser .up.|> Parser
+XYZTYPECommand -up-|> XYZAbstractCommand
+XYZTYPECommandParser -up-|> Type
+ArgumentTokenizer .left.> ArgumentMultimap
CliSyntax ..> Prefix
XYZCommandParser ..> ParserUtil
ParserUtil .down.> Prefix
ArgumentTokenizer .down.> Prefix
+XYZAbstractCommand -right-|> Command
XYZCommand -up-|> Command
+XYZCommandParser ..> XYZTYPECommandParser: creates >
+
+
@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..c14605e5720 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -19,7 +19,8 @@ Class "<>\nAddressBookStorage" as AddressBookStorage
Class JsonAddressBookStorage
Class JsonSerializableAddressBook
Class JsonAdaptedPerson
-Class JsonAdaptedTag
+Class JsonAdaptedInterview
+Class JsonAdaptedTask
}
}
@@ -37,7 +38,9 @@ Storage -right-|> AddressBookStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
JsonAddressBookStorage .up.|> AddressBookStorage
JsonAddressBookStorage ..> JsonSerializableAddressBook
+JsonSerializableAddressBook --> "*" JsonAdaptedInterview
+JsonAdaptedInterview --> "1" JsonAdaptedPerson
JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonSerializableAddressBook --> "*" JsonAdaptedTask
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..716396da77d 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -15,6 +15,10 @@ Class PersonListPanel
Class PersonCard
Class StatusBarFooter
Class CommandBox
+Class InterviewListPanel
+Class InterviewCard
+Class TaskListPanel
+Class TaskCard
}
package Model <> {
@@ -35,8 +39,12 @@ MainWindow *-down-> "1" ResultDisplay
MainWindow *-down-> "1" PersonListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
+MainWindow *-down-> "1" InterviewListPanel
+MainWindow *-down-> "1" TaskListPanel
PersonListPanel -down-> "*" PersonCard
+InterviewListPanel -down-> "*" InterviewCard
+TaskListPanel -down-> "*" TaskCard
MainWindow -left-|> UiPart
@@ -46,12 +54,18 @@ PersonListPanel --|> UiPart
PersonCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
+InterviewListPanel --|> UiPart
+TaskListPanel --|> UiPart
PersonCard ..> Model
+InterviewCard ..> Model
+TaskCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
PersonListPanel -[hidden]left- HelpWindow
+InterviewListPanel -[hidden]left- HelpWindow
+TaskListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..f9033eb8451 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 1ec62caa2a5..5e635abe7da 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..76ff6ddd5f2 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/ExportSequenceDiagram.png b/docs/images/ExportSequenceDiagram.png
new file mode 100644
index 00000000000..7e4c6cf1830
Binary files /dev/null and b/docs/images/ExportSequenceDiagram.png differ
diff --git a/docs/images/FindCommandSequenceDiagram.png b/docs/images/FindCommandSequenceDiagram.png
new file mode 100644
index 00000000000..ae1f05de951
Binary files /dev/null and b/docs/images/FindCommandSequenceDiagram.png differ
diff --git a/docs/images/ImportCheckSequenceDiagram.png b/docs/images/ImportCheckSequenceDiagram.png
new file mode 100644
index 00000000000..647761880e9
Binary files /dev/null and b/docs/images/ImportCheckSequenceDiagram.png differ
diff --git a/docs/images/ImportSequenceDiagram.png b/docs/images/ImportSequenceDiagram.png
new file mode 100644
index 00000000000..aea94429807
Binary files /dev/null and b/docs/images/ImportSequenceDiagram.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 9e9ba9f79e5..e2ab294c66b 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index 04070af60d8..e20d79f7b75 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
index e7b4c8880cd..f9427a59178 100644
Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..66e260019a5 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..3f4f9339b6b 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 785e04dbab4..3277ae6c234 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/add-applicant.png b/docs/images/add-applicant.png
new file mode 100644
index 00000000000..3ff490e2de7
Binary files /dev/null and b/docs/images/add-applicant.png differ
diff --git a/docs/images/add-interview.png b/docs/images/add-interview.png
new file mode 100644
index 00000000000..5ed87d3ba3d
Binary files /dev/null and b/docs/images/add-interview.png differ
diff --git a/docs/images/add-task.PNG b/docs/images/add-task.PNG
new file mode 100644
index 00000000000..6a2c572b60a
Binary files /dev/null and b/docs/images/add-task.PNG differ
diff --git a/docs/images/after-edit-contact-2.png b/docs/images/after-edit-contact-2.png
new file mode 100644
index 00000000000..b418039db53
Binary files /dev/null and b/docs/images/after-edit-contact-2.png differ
diff --git a/docs/images/after-edit-contact-3.png b/docs/images/after-edit-contact-3.png
new file mode 100644
index 00000000000..f497c95342f
Binary files /dev/null and b/docs/images/after-edit-contact-3.png differ
diff --git a/docs/images/after-edit-contact.png b/docs/images/after-edit-contact.png
new file mode 100644
index 00000000000..64c4acb3ca0
Binary files /dev/null and b/docs/images/after-edit-contact.png differ
diff --git a/docs/images/alltogether.PNG b/docs/images/alltogether.PNG
new file mode 100644
index 00000000000..9700c08daaa
Binary files /dev/null and b/docs/images/alltogether.PNG differ
diff --git a/docs/images/before-edit-contact-2.png b/docs/images/before-edit-contact-2.png
new file mode 100644
index 00000000000..56252f48427
Binary files /dev/null and b/docs/images/before-edit-contact-2.png differ
diff --git a/docs/images/before-edit-contact-3.png b/docs/images/before-edit-contact-3.png
new file mode 100644
index 00000000000..11dace48a68
Binary files /dev/null and b/docs/images/before-edit-contact-3.png differ
diff --git a/docs/images/before-edit-contact.png b/docs/images/before-edit-contact.png
new file mode 100644
index 00000000000..56252f48427
Binary files /dev/null and b/docs/images/before-edit-contact.png differ
diff --git a/docs/images/brigittesantoso.png b/docs/images/brigittesantoso.png
new file mode 100644
index 00000000000..fc5712a3d7a
Binary files /dev/null and b/docs/images/brigittesantoso.png differ
diff --git a/docs/images/edit-interview-1.PNG b/docs/images/edit-interview-1.PNG
new file mode 100644
index 00000000000..82abef32154
Binary files /dev/null and b/docs/images/edit-interview-1.PNG differ
diff --git a/docs/images/edit-interview.png b/docs/images/edit-interview.png
new file mode 100644
index 00000000000..d9da337e19d
Binary files /dev/null and b/docs/images/edit-interview.png differ
diff --git a/docs/images/edit-task-2.PNG b/docs/images/edit-task-2.PNG
new file mode 100644
index 00000000000..e666506966a
Binary files /dev/null and b/docs/images/edit-task-2.PNG differ
diff --git a/docs/images/edit-task.PNG b/docs/images/edit-task.PNG
new file mode 100644
index 00000000000..f2fcbb5bfc7
Binary files /dev/null and b/docs/images/edit-task.PNG differ
diff --git a/docs/images/eman-kom.png b/docs/images/eman-kom.png
new file mode 100644
index 00000000000..1ce7ce16dc8
Binary files /dev/null and b/docs/images/eman-kom.png differ
diff --git a/docs/images/find-applicant-AND-OR-example.png b/docs/images/find-applicant-AND-OR-example.png
new file mode 100644
index 00000000000..f71800e0a11
Binary files /dev/null and b/docs/images/find-applicant-AND-OR-example.png differ
diff --git a/docs/images/find-applicant-AND-example.png b/docs/images/find-applicant-AND-example.png
new file mode 100644
index 00000000000..71850df12b3
Binary files /dev/null and b/docs/images/find-applicant-AND-example.png differ
diff --git a/docs/images/find-applicant-OR-example.png b/docs/images/find-applicant-OR-example.png
new file mode 100644
index 00000000000..f92d85942ac
Binary files /dev/null and b/docs/images/find-applicant-OR-example.png differ
diff --git a/docs/images/find-interview-AND-OR-example.PNG b/docs/images/find-interview-AND-OR-example.PNG
new file mode 100644
index 00000000000..368f20c342c
Binary files /dev/null and b/docs/images/find-interview-AND-OR-example.PNG differ
diff --git a/docs/images/find-interview-AND-example.PNG b/docs/images/find-interview-AND-example.PNG
new file mode 100644
index 00000000000..3316c8cc407
Binary files /dev/null and b/docs/images/find-interview-AND-example.PNG differ
diff --git a/docs/images/find-interview-OR-example.PNG b/docs/images/find-interview-OR-example.PNG
new file mode 100644
index 00000000000..48830607555
Binary files /dev/null and b/docs/images/find-interview-OR-example.PNG differ
diff --git a/docs/images/find-interview.png b/docs/images/find-interview.png
new file mode 100644
index 00000000000..2d5eed8fe89
Binary files /dev/null and b/docs/images/find-interview.png differ
diff --git a/docs/images/find-task-AND-OR-example.PNG b/docs/images/find-task-AND-OR-example.PNG
new file mode 100644
index 00000000000..f824b71e55f
Binary files /dev/null and b/docs/images/find-task-AND-OR-example.PNG differ
diff --git a/docs/images/find-task-AND-example.PNG b/docs/images/find-task-AND-example.PNG
new file mode 100644
index 00000000000..dec1646282f
Binary files /dev/null and b/docs/images/find-task-AND-example.PNG differ
diff --git a/docs/images/find-task-OR-example.PNG b/docs/images/find-task-OR-example.PNG
new file mode 100644
index 00000000000..e94b915af18
Binary files /dev/null and b/docs/images/find-task-OR-example.PNG differ
diff --git a/docs/images/find.png b/docs/images/find.png
new file mode 100644
index 00000000000..48622151a09
Binary files /dev/null and b/docs/images/find.png differ
diff --git a/docs/images/imrajsinghsandhu.png b/docs/images/imrajsinghsandhu.png
new file mode 100644
index 00000000000..895007a54f3
Binary files /dev/null and b/docs/images/imrajsinghsandhu.png differ
diff --git a/docs/images/rcjj98.png b/docs/images/rcjj98.png
new file mode 100644
index 00000000000..878ad88717f
Binary files /dev/null and b/docs/images/rcjj98.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..0209422465f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,17 @@
---
layout: page
-title: AddressBook Level-3
+title: HRConnect Level-3
---
[](https://github.com/se-edu/addressbook-level3/actions)
-[](https://codecov.io/gh/se-edu/addressbook-level3)
+[](https://codecov.io/gh/AY2122S2-CS2103T-W11-2/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).
+**HRConnect is a desktop application for tech HR recruiters to manage job applicants, interviews and miscellaneous tasks.** 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 HRConnect, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing HRConnect, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/docs/team/brigittesantoso.md b/docs/team/brigittesantoso.md
new file mode 100644
index 00000000000..1add83e0501
--- /dev/null
+++ b/docs/team/brigittesantoso.md
@@ -0,0 +1,53 @@
+---
+layout: page
+title: Brigitte Santoso's Project Portfolio Page
+---
+
+## Project: HRConnect
+
+HRConnect is an application for managing job applicants, interviews and miscellaneous tasks.
+Given below are my contributions to the project.
+
+### Enhancements implemented
+* **Job and Stage fields**: Added `Job` and `Stage` attributes to `Person` class
+ * What it does: Clearly indicate which job position an applicant is applying to and which stage progress they are currently at
+ * Justification: This feature improves the product significantly as the main aim of our application for HR recruiters to manage the job applicants and their stage progress easily.
+* **Interview Feature**: Added a tab to showcase list of interviews along with its various commands
+ * What it does: Allows the user to `add`, `delete`, `edit`, `list` and `clear` interviews.
+ * Justification: This feature improves the product significantly as it allows HR recruiters to easily keep track of the interviews they have with each applicant. The add, delete, edit, list and clear commands help fulfill the possible changes that the user might make to the list.
+ * Highlights: This enhancement affects existing commands as the `Person` is an attribute in the `Interview` class thus edits have to be made with some of the `Person` commands.
+* **Types**: Introduced types into code to distinguish between applicant, interview and task
+ * What it does: Allows the user to differentiate between which list they are updating by adding either `[p]`, `[i]` or `[t]` behind each command.
+ * Justification: This feature improves the product significantly as it helps to standardise command line conventions and make it less confusing and easier to differentiate between different types of commands.
+ * Highlights: This enhancement was difficult as it requires abstraction of code such as creating an abstract class `AddCommand` which `AddPersonCommand`, `AddInterviewCommand` and `AddTaskCommand` extends from to reduce the amount of duplicate code and ensure that OOP principles are adhered to.
+
+### Code Contribution
+Link: Code Contributed
+
+### Contributions to the UG and DG
+**UG**
+* Add all Task commands to the UG with clear formatting
+* Add constraint pointers to some commands
+ * e.g. `clearing applicant list` and `adding interview`
+* Add notes for Interview and Task features
+ * Listed in chronological date time order
+* Solve some UG bugs highlighted from PED
+* Helped to format the UG by adding appropriate page breaks for PDF submission
+
+**DG**
+* Edited Model and Storage sections of DG along with their elaboration
+* Edited UML diagrams for Model and Storage section
+ * `BetterModelClassDiagram`, `ModelClassDiagram` and `StorageClassDiagram`
+* Helped to format the DG by adding appropriate page breaks for PDF submission
+
+### Contributions to team-based tasks
+
+* Created a few milestones and issues for team
+* Ensure team completes all team-based tasks on time
+
+### Review/mentoring contributions
+
+* Reviewed and approved some team members PRs with some comments and suggestions
+* Helped to solve bugs and issues in other team members features
+* Bugs reported in other team products during PED
+ * Link: PED Issues
diff --git a/docs/team/eman-kom.md b/docs/team/eman-kom.md
new file mode 100644
index 00000000000..7c550971a80
--- /dev/null
+++ b/docs/team/eman-kom.md
@@ -0,0 +1,78 @@
+---
+layout: page
+title: Emmanuel Mok's Project Portfolio Page
+---
+
+### Project: HRConnect
+
+This product is for tech HR recruiters who prefer to use CLI to store contacts of job applicants and their respective interviews as well as keep track of the status of each applicant through the application process.
+
+
+Given below are my contributions to the project.
+
+* **New Feature:** Added more flexibility to the `find` command.
+ * What it does: Allows users to search of any data in their respective sections (Task/Interview/Applicant)
+ using the flags as defined in the app. It also simulates 'AND' and 'OR' statements through the use of
+ the `g/` flag.
+ * Justification: The previous `find` command was too simplistic in the sense that it can only search for names. With
+ more data fields being added to HRConnect, a stronger search function is required to enable users to effectively
+ look for data that they are searching for. Furthermore, the simulation of 'AND' and 'OR' commands gives users more
+ flexibility and control over their search criteria, leading to a better experience for the user.
+ * Highlights: This enhancement improves upon the original `find` command. Hence, it requires some analysis into other
+ design considerations to ensure that the enhancement is both intuitive and useful to the user. It was also challenging to
+ implement a custom `g/` flag for the `find` command as it requires custom validity checks which builds upon the
+ ArgumentTokenizer and ArgumentMultiMap.
+
+* **New Feature:** Added an `import` feature to allow job applicants data to be transferred into the address book.
+ * What it does: Allows users to import all job applicants data from a csv save file that was previously
+ exported out by the `export` command.
+ * Justification: This feature is complementary to the `export` command it allows previously exported data to be
+ reintegrated back into the address book.
+ * Highlights: This enhancement was challenging because the csv save file can be subjected to a lot of other changes by
+ the user. A lot of checks are needed to ensure that the contents of the csv save file contents adhere to the flag
+ formats as defined in the HRConnect app. Furthermore, there is also a check for any duplicates for both within the csv save
+ file and the app itself before adding all the job applicants to the app.
+
+
+* **Code Contributed:**
+ * [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=eman-kom&breakdown=true)
+
+
+* **Project Management:**
+ * Released v1.3 on GitHub ([v1.3 release link](https://github.com/AY2122S2-CS2103T-W11-2/tp/releases/tag/v1.3))
+ * Enabled Assertions (Pull Request: [#45](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/45/commits/a0eda15e3016f5416a577dd3256d984753862229))
+ * Created the GitHub organization repo
+
+
+* **Enhancement to existing features:**
+ * Updated the help page in the address book (Pull Request: [#78](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/78/files))
+ * Changed the application name of the address book (Pull Request: [#94](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/94/files))
+
+
+* **Documentation:**
+ * User Guide:
+ * Drafted the initial version of the UG (Pull request: [#53](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/53))
+ * Drafted the Flags and Parameters Format Constraints & Section Types (Pull request: [#168](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/168/files))
+ * Wrote the Find Feature (Task, Interview & Applicant) in the UG
+ * Wrote the Import Feature in the UG
+
+ * Developer Guide:
+ * Added implementation details of the `find` feature
+ * Added implementation details of the `export` feature
+ * Added implementation details of the `import` feature
+
+
+* **Team:**
+ * Fixed some merge conflicts
+ * Helped to find and fix some bugs
+ * Reviewed some PRs (Pull Requests:
+ [#43](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/43),
+ [#50](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/50),
+ [#54](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/54),
+ [#41](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/41))
+ * Assisted team members in resolving any obstacles they face
+
+
+* **Community:**
+ * Submitted 22 bugs for the other team in the PE dry run. ([PED link](https://github.com/eman-kom/ped/issues))
+
diff --git a/docs/team/imrajsinghsandhu.md b/docs/team/imrajsinghsandhu.md
new file mode 100644
index 00000000000..af25c0f7837
--- /dev/null
+++ b/docs/team/imrajsinghsandhu.md
@@ -0,0 +1,62 @@
+---
+layout: page
+title: Imraj Singh's Project Portfolio Page
+---
+
+### Project: HRConnect
+
+HRConnect is a desktop address book application used for keeping track of job applicants' details during their entire application process. It is a CLI focused application, whereby users will interect with the program with commands. The GUI of this application is created with JavaFX, and the application as around 10 kLoC wrtitten in Java.
+
+Given below are the contributions I have made to this project.
+
+## Task Feature
+
+* What it does: Allows users to be able to add a task that has to be done
+* Justification: This feature allows the user to note down any miscellaneous tasks that are to be completed
+
+## Code contributed
+
+* [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=imrajsinghsandhu&breakdown=true)
+
+## Enhancements implemented
+
+* Implemented the add task feature
+* Adhered to OOP principles to reduce the repetition of code
+
+## Contributions to the Developer Guide
+
+* Added on to the ParserClassDiagram
+* Edited the DeleteSequenceDiagram to include more classes and method
+* Edited the LogicClassDiagram
+* Added on to the UiClassDiagram
+* Changed the descriptions of the above mentioned components
+* Edited some bugs found on the Developer Guide
+
+## Contributions to the User Guide
+
+* User Guide:
+ * Added use cases for the delete feature
+ * Reshuffled the orders of some of the commands in command summary table
+ * Changed the design of the features section
+ * Solved some bugs as was highighted in the PE-D
+
+## Team
+
+* Brainstormed user stories and product features with team
+* Reviewed the following PRs:
+[#159](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/159)
+[#54](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/54)
+[#41](https://github.com/AY2122S2-CS2103T-W11-2/tp/pull/41)
+
+## Code Review contributions
+
+* Reviewed and approved team members' PRs with comments and suggestions for improvments where necessary
+* Helped with checkstyle edits of files
+
+## Leadership & Initiative
+
+* Helped teammates with bug fixes and understanding of tasks/code
+
+## Bug reports
+
+* Tested products of other groups and provided bug reports
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index 773a07794e2..00000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: page
-title: John Doe's Project Portfolio Page
----
-
-### Project: AddressBook Level 3
-
-AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
-
-Given below are my contributions to the project.
-
-* **New Feature**: Added the ability to undo/redo previous commands.
- * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
- * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
- * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
- * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
-
-* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
-
-* **Code contributed**: [RepoSense link]()
-
-* **Project management**:
- * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
-
-* **Enhancements to existing features**:
- * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
- * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
-
-* **Documentation**:
- * User Guide:
- * Added documentation for the features `delete` and `find` [\#72]()
- * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
- * Developer Guide:
- * Added implementation details of the `delete` feature.
-
-* **Community**:
- * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
- * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
- * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
- * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
-
-* **Tools**:
- * Integrated a third party library (Natty) to the project ([\#42]())
- * Integrated a new Github plugin (CircleCI) to the team repo
-
-* _{you can add/remove categories in the list above}_
diff --git a/docs/team/rcjj98.md b/docs/team/rcjj98.md
new file mode 100644
index 00000000000..4915e39720b
--- /dev/null
+++ b/docs/team/rcjj98.md
@@ -0,0 +1,66 @@
+---
+layout: page
+title: Ryan Chang's Project Portfolio Page
+---
+
+### Project: HRConnect
+
+HRConnect is a desktop application for managing the contacts of job applicants. It can also be used to keep track of the
+progress of each applicant during the application process.
+
+Given below are my contributions to the project.
+
+# Summary of Contributions
+
+## Code contributed
+
+[RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=rcjj98&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2022-02-18&tabOpen=true&tabType=zoom&zFR=false&zA=rcjj98&zR=AY2122S2-CS2103T-W11-2%2Ftp%5Bmaster%5D&zACS=198.13128430296376&zS=2022-02-18&zFS=&zU=2022-04-08&zMG=false&zFTF=commit&zFGS=groupByRepos)
+
+## Enhancements implemented
+
+* **Edit Feature**: Added the ability to edit details of job applicants.
+ * What it does: Allows the user to update any current details of job applicants that were added previously.
+ * Justification: This feature improves the product significantly because a user can make mistakes when adding a new
+ job applicant and the app should provide a convenient way to rectify them.
+
+
+* **Export Feature**: Added the ability to export the data from the application to a csv file.
+ * What it does: Allows the user to export all applicant data to a csv save file for archiving.
+ * Justification: This feature improves the product significantly because a user's address book can start to fill up
+ with contacts that are no longer important and the application should provide a convenient way to export data to a
+ file to allow users the convenience of making a copy before clearing the data.
+
+
+* Abstract main idea from code to reduce repetition.
+
+* Checked and reformat code that violated java coding standards.
+
+## Contributions to the UG
+
+* Add all applicant commands to the UG with proper formatting.
+* Updated commands in the command summary table to match valid command usage.
+* Add warning messages for editing applicant.
+* Resolved some Pe-D issues.
+* Finalize bulk of the applicant commands format for the UG.
+
+## Contributions to the DG
+
+* Edited Appendix: Requirements.
+* Edited Appendix: Instructions for manual testing.
+
+## Contributions to team-based tasks
+
+* Created milestone v1.2 and several issues for team repo.
+* Facilitated smooth communications during team meetings using interpersonal skills.
+* Handled submissions of tP final submissions.
+
+## Review/mentoring contributions
+
+* Reviewed and approved multiple PRs with tactful comments and suggestions.
+* Suggested alternative solutions to some problems faced during team meetings.
+* Objectively discussed which tasks were well suited for each team member to ensure efficient delegation of work.
+
+## Contributions beyond team-projects
+
+* Ensure team dynamics was well maintained throughout entire semester.
+* Checking up on teammates progress intermittently during the semester to build rapport.
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 4133aaa0151..dafba60d584 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -36,7 +36,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 3, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -56,6 +56,7 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
+
AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
storage = new StorageManager(addressBookStorage, userPrefsStorage);
@@ -155,7 +156,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
initializedPrefs = new UserPrefs();
}
- //Update prefs file in case it was missing to begin with or there are new/unused fields
+ // Update prefs file in case it was missing to begin with or there are new/unused fields
try {
storage.saveUserPrefs(initializedPrefs);
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
index 1deb3a1e469..b2e195a14d4 100644
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ b/src/main/java/seedu/address/commons/core/Messages.java
@@ -7,7 +7,17 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
-
+ public static final String MESSAGE_INVALID_INTERVIEW_DISPLAYED_INDEX = "The interview index provided is invalid";
+ public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The applicant index provided is invalid";
+ public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid";
+ public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d applicants listed!";
+ public static final String MESSAGE_INTERVIEWS_LISTED_OVERVIEW = "%1$d interviews listed!";
+ public static final String MESSAGE_TASKS_LISTED_OVERVIEW = "%1$d tasks listed!";
+ public static final String MESSAGE_NO_TYPE_GIVEN = "No type given. Type should be either [p] or [i] or [t].";
+ public static final String MESSAGE_INVALID_TYPE_GIVEN = "Invalid type given. Type should be either [p] or [i]"
+ + " or [t].";
+ public static final String MESSAGE_INTERVIEW_LIST_NOT_EMPTY = "Interview list is not empty. "
+ + "Please clear interview list first.";
+ public static final String MESSAGE_PERSON_HAS_INTERVIEW = "Applicant has interview. "
+ + "Delete interview first before editing or deleting applicant.";
}
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/address/commons/util/FileUtil.java
index b1e2767cdd9..b537ece3039 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/address/commons/util/FileUtil.java
@@ -5,6 +5,7 @@
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
/**
* Writes and reads files
@@ -72,6 +73,17 @@ public static String readFromFile(Path file) throws IOException {
return new String(Files.readAllBytes(file), CHARSET);
}
+ /**
+ * Reads all lines from a file.
+ *
+ * @param file Input file
+ * @return A list of lines from the file
+ * @throws IOException Error occurred while reading.
+ */
+ public static List readFromFileLines(Path file) throws IOException {
+ return Files.readAllLines(file);
+ }
+
/**
* Writes given string to a file.
* Will create the file if it does not exist yet.
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..08bad7e9090 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -8,7 +8,9 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
/**
* API of the Logic component
@@ -33,6 +35,12 @@ public interface Logic {
/** Returns an unmodifiable view of the filtered list of persons */
ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered list of interviews */
+ ObservableList getFilteredInterviewList();
+
+ /** Returns an unmodifiable view of the filtered list of tasks */
+ ObservableList getFilteredTaskList();
+
/**
* Returns the user prefs' address book file path.
*/
@@ -47,4 +55,7 @@ public interface Logic {
* Set the user prefs' GUI settings.
*/
void setGuiSettings(GuiSettings guiSettings);
+
+
+
}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 9d9c6d15bdc..52ea6f58a4d 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -14,7 +14,9 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
import seedu.address.storage.Storage;
/**
@@ -64,6 +66,16 @@ public ObservableList getFilteredPersonList() {
return model.getFilteredPersonList();
}
+ @Override
+ public ObservableList getFilteredInterviewList() {
+ return model.getFilteredInterviewList();
+ }
+
+ @Override
+ public ObservableList getFilteredTaskList() {
+ return model.getFilteredTaskList();
+ }
+
@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
@@ -78,4 +90,5 @@ public GuiSettings getGuiSettings() {
public void setGuiSettings(GuiSettings guiSettings) {
model.setGuiSettings(guiSettings);
}
+
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 71656d7c5c8..590203031e7 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -1,67 +1,15 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-/**
- * Adds a person to the address book.
- */
-public class AddCommand extends Command {
+public abstract 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 "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
-
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
- private final Person toAdd;
-
- /**
- * Creates an AddCommand to add the specified {@code Person}
- */
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
- }
-
@Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
-
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- }
+ public abstract CommandResult execute(Model model) throws CommandException;
@Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddCommand // instanceof handles nulls
- && toAdd.equals(((AddCommand) other).toAdd));
- }
+ public abstract boolean equals(Object other);
}
diff --git a/src/main/java/seedu/address/logic/commands/AddInterviewCommand.java b/src/main/java/seedu/address/logic/commands/AddInterviewCommand.java
new file mode 100644
index 00000000000..70b2069a5aa
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddInterviewCommand.java
@@ -0,0 +1,97 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Date;
+import seedu.address.model.Model;
+import seedu.address.model.Time;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.person.Person;
+
+/**
+ * Adds an interview to the address book.
+ */
+public class AddInterviewCommand extends AddCommand {
+
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [i] : Adds an interview to the interview list "
+ + "by the index number used in the displayed applicant list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_DATE + "DATE "
+ + PREFIX_TIME + "TIME\n"
+ + "Example: " + COMMAND_WORD + " [i] 1 "
+ + PREFIX_DATE + "2021-05-06 "
+ + PREFIX_TIME + "05:29";
+
+
+ public static final String MESSAGE_SUCCESS = "Added Interview: %1$s";
+ public static final String MESSAGE_DUPLICATE_INTERVIEW = "This interview already exists in the interview list";
+
+ private final Index index;
+ private final Date date;
+ private final Time time;
+
+ /**
+ * Creates an AddInterviewCommand to add the specified {@code Interview}
+ */
+ public AddInterviewCommand(Index index, Date date, Time time) {
+ requireNonNull(index);
+ requireNonNull(date);
+ requireNonNull(time);
+ this.index = index;
+ this.date = date;
+ this.time = time;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredPersonList();
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToInterview = lastShownList.get(index.getZeroBased());
+ Interview toAdd = createInterview(personToInterview, date, time);
+
+ if (model.hasInterview(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERVIEW);
+ }
+
+ model.addInterview(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd), getType());
+ }
+
+ /**
+ * Creates and returns a {@code Interview}.
+ */
+ private static Interview createInterview(Person personToInterview, Date date, Time time) {
+ assert personToInterview != null;
+
+ return new Interview(personToInterview, date, time);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddInterviewCommand // instanceof handles nulls
+ && index.equals(((AddInterviewCommand) other).index)
+ && date.equals(((AddInterviewCommand) other).date)
+ && time.equals(((AddInterviewCommand) other).time));
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddPersonCommand.java b/src/main/java/seedu/address/logic/commands/AddPersonCommand.java
new file mode 100644
index 00000000000..e73d130830b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddPersonCommand.java
@@ -0,0 +1,74 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+
+/**
+ * Adds an applicant to the address book.
+ */
+public class AddPersonCommand extends AddCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [p] : Adds an applicant to the applicant list.\n"
+ + "Parameters: "
+ + PREFIX_NAME + "NAME "
+ + PREFIX_PHONE + "PHONE "
+ + PREFIX_EMAIL + "EMAIL "
+ + PREFIX_ADDRESS + "ADDRESS "
+ + PREFIX_JOB + "JOB "
+ + PREFIX_STAGE + "STAGE\n"
+ + "Example: " + COMMAND_WORD + " [p] "
+ + PREFIX_NAME + "John Doe "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_EMAIL + "johnd@example.com "
+ + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
+ + PREFIX_JOB + "Software Engineer "
+ + PREFIX_STAGE + "INPROGRESS";
+
+ public static final String MESSAGE_SUCCESS = "Added Applicant: %1$s";
+ public static final String MESSAGE_DUPLICATE_PERSON = "This applicant already exists in the applicant list";
+
+ private final Person toAdd;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Person}
+ */
+ public AddPersonCommand(Person person) {
+ requireNonNull(person);
+ toAdd = person;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasPerson(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ }
+
+ model.addPerson(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd), getType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddPersonCommand // instanceof handles nulls
+ && toAdd.equals(((AddPersonCommand) other).toAdd));
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddTaskCommand.java b/src/main/java/seedu/address/logic/commands/AddTaskCommand.java
new file mode 100644
index 00000000000..1c7983675dc
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddTaskCommand.java
@@ -0,0 +1,69 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+import static seedu.address.logic.parser.Type.TASK;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.tasks.Task;
+
+/**
+ * Adds a task to the address book.
+ */
+public class AddTaskCommand extends AddCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [t] : Adds a task to the list of tasks.\n"
+ + "Parameters: "
+ + PREFIX_HEADER + "HEADER "
+ + PREFIX_DATE + "DATE "
+ + PREFIX_TIME + "TIME "
+ + PREFIX_INFORMATION + "INFORMATION\n"
+ + "Example: " + COMMAND_WORD + " [t] "
+ + PREFIX_HEADER + "Update interview statuses "
+ + PREFIX_DATE + "2021-05-06 "
+ + PREFIX_TIME + "05:29 "
+ + PREFIX_INFORMATION + "Update all interview statuses to ACCEPTED";
+
+ public static final String MESSAGE_SUCCESS = "Added Task: %1$s";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task list";
+
+ public final Task toAdd;
+
+ /**
+ * Constructor for AddTaskCommand.
+ * @param task Task to be added
+ */
+ public AddTaskCommand(Task task) {
+ requireNonNull(task);
+ toAdd = task;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasTask(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ }
+
+ model.addTask(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd), getType());
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddTaskCommand // instanceof handles nulls
+ && toAdd.equals(((AddTaskCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..1a8cb32cc33 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -1,23 +1,18 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.model.AddressBook;
+import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
/**
* Clears the address book.
*/
-public class ClearCommand extends Command {
+public abstract class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [p] to clear all applicants"
+ + " or [i] to clear all interviews" + " or [t] to clear all tasks";
@Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
- }
+ public abstract CommandResult execute(Model model) throws CommandException;
+
}
diff --git a/src/main/java/seedu/address/logic/commands/ClearInterviewCommand.java b/src/main/java/seedu/address/logic/commands/ClearInterviewCommand.java
new file mode 100644
index 00000000000..13c0ed0a7df
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ClearInterviewCommand.java
@@ -0,0 +1,24 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ClearInterviewCommand extends ClearCommand {
+ public static final String MESSAGE_SUCCESS = "Interviews have all been cleared!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.resetInterviews();
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/ClearPersonCommand.java b/src/main/java/seedu/address/logic/commands/ClearPersonCommand.java
new file mode 100644
index 00000000000..cd7516375a7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ClearPersonCommand.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INTERVIEW_LIST_NOT_EMPTY;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ClearPersonCommand extends ClearCommand {
+ public static final String MESSAGE_SUCCESS = "Applicants have all been cleared!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ if (model.getFilteredInterviewList().isEmpty()) {
+ model.resetPersons();
+ } else {
+ throw new CommandException(MESSAGE_INTERVIEW_LIST_NOT_EMPTY);
+ }
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearTaskCommand.java b/src/main/java/seedu/address/logic/commands/ClearTaskCommand.java
new file mode 100644
index 00000000000..6042695c40f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ClearTaskCommand.java
@@ -0,0 +1,23 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.TASK;
+
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ClearTaskCommand extends ClearCommand {
+ public static final String MESSAGE_SUCCESS = "Tasks have all been cleared!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.resetTasks();
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/address/logic/commands/Command.java
index 64f18992160..46d6388075d 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/address/logic/commands/Command.java
@@ -1,6 +1,7 @@
package seedu.address.logic.commands;
import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
import seedu.address.model.Model;
/**
@@ -17,4 +18,7 @@ public abstract class Command {
*/
public abstract CommandResult execute(Model model) throws CommandException;
+ public Type getType() {
+ return null;
+ }
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 92f900b7916..07c5df79cc9 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -4,6 +4,8 @@
import java.util.Objects;
+import seedu.address.logic.parser.Type;
+
/**
* Represents the result of a command execution.
*/
@@ -11,6 +13,8 @@ public class CommandResult {
private final String feedbackToUser;
+ private final Type type;
+
/** Help information should be shown to the user. */
private final boolean showHelp;
@@ -20,8 +24,9 @@ public class CommandResult {
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, Type type, boolean showHelp, boolean exit) {
this.feedbackToUser = requireNonNull(feedbackToUser);
+ this.type = type;
this.showHelp = showHelp;
this.exit = exit;
}
@@ -30,14 +35,18 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
* and other fields set to their default value.
*/
- public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
+ public CommandResult(String feedbackToUser, Type type) {
+ this(feedbackToUser, type, false, false);
}
public String getFeedbackToUser() {
return feedbackToUser;
}
+ public Type getType() {
+ return type;
+ }
+
public boolean isShowHelp() {
return showHelp;
}
@@ -59,13 +68,14 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
+ && type == otherCommandResult.type
&& showHelp == otherCommandResult.showHelp
&& exit == otherCommandResult.exit;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, type, showHelp, exit);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 02fd256acba..c6123a4faee 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -1,53 +1,16 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-/**
- * Deletes a person identified using it's displayed index from the address book.
- */
-public class DeleteCommand extends Command {
+public abstract class DeleteCommand extends Command {
public static final String COMMAND_WORD = "delete";
- public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
-
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
-
- private final Index targetIndex;
-
- public DeleteCommand(Index targetIndex) {
- this.targetIndex = targetIndex;
- }
-
@Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
- }
+ public abstract CommandResult execute(Model model) throws CommandException;
@Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof DeleteCommand // instanceof handles nulls
- && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check
- }
+ public abstract boolean equals(Object other);
+
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteInterviewCommand.java b/src/main/java/seedu/address/logic/commands/DeleteInterviewCommand.java
new file mode 100644
index 00000000000..7262edd4d8f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteInterviewCommand.java
@@ -0,0 +1,60 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.interview.Interview;
+
+public class DeleteInterviewCommand extends DeleteCommand {
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [i] : Deletes the interview identified by the index number used in the displayed interview list,\n"
+ + "Parameters: INDEX (must be a positive integer),\n"
+ + "Example: " + COMMAND_WORD + " [i] 1\n";
+
+
+ public static final String MESSAGE_DELETE_INTERVIEW_SUCCESS = "Deleted Interview: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructor for DeleteInterviewCommand.
+ * @param targetIndex
+ */
+ public DeleteInterviewCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInterviewList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_INTERVIEW_DISPLAYED_INDEX);
+ }
+ Interview interviewToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteInterview(interviewToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_INTERVIEW_SUCCESS, interviewToDelete), getType());
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteInterviewCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteInterviewCommand) other).targetIndex)); // state check
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/DeletePersonCommand.java b/src/main/java/seedu/address/logic/commands/DeletePersonCommand.java
new file mode 100644
index 00000000000..dce4d7b7cf9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeletePersonCommand.java
@@ -0,0 +1,85 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_PERSON_HAS_INTERVIEW;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.person.Person;
+
+public class DeletePersonCommand extends DeleteCommand {
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [p] : Deletes the applicant identified by the index number used in the displayed applicant list,\n"
+ + "Parameters: INDEX (must be a positive integer),\n"
+ + "Example: " + COMMAND_WORD + " [p] 1\n";
+
+ public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Applicant: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructor for DeletePersonCommand.
+ * @param targetIndex
+ */
+ public DeletePersonCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownPersonList = model.getFilteredPersonList();
+
+ if (targetIndex.getZeroBased() >= lastShownPersonList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToDelete = lastShownPersonList.get(targetIndex.getZeroBased());
+
+ if (personHasInterview(personToDelete, model)) {
+ throw new CommandException(MESSAGE_PERSON_HAS_INTERVIEW);
+ }
+
+ model.deletePerson(personToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete), getType());
+ }
+
+ /**
+ * Check if applicant that we wish to delete has interview
+ *
+ * @param person applicant
+ * @param model model
+ * @return true if applicant has interview
+ */
+ public boolean personHasInterview(Person person, Model model) {
+ List lastShownInterviewList = model.getFilteredInterviewList();
+ for (int i = 0; i < lastShownInterviewList.size(); i++) {
+ if (lastShownInterviewList.get(i).getPerson().equals(person)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeletePersonCommand // instanceof handles nulls
+ && targetIndex.equals(((DeletePersonCommand) other).targetIndex)); // state check
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
+
+
diff --git a/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java
new file mode 100644
index 00000000000..f938448222f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteTaskCommand.java
@@ -0,0 +1,56 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.TASK;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.tasks.Task;
+
+public class DeleteTaskCommand extends DeleteCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [t] : Deletes the task identified by the index number used in the displayed task list,\n"
+ + "Parameters: INDEX (must be a positive integer),\n "
+ + "Example: " + COMMAND_WORD + " [t] 1\n";
+
+ public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted Task: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructor for DeleteTaskCommand.
+ * @param targetIndex
+ */
+ public DeleteTaskCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredTaskList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+ Task taskToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteTask(taskToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete), getType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return false;
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 7e36114902f..5dd59d57a9e 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -1,226 +1,15 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.CollectionUtil;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-/**
- * Edits the details of an existing person in the address book.
- */
-public class EditCommand extends Command {
+public abstract class EditCommand extends Command {
public static final String COMMAND_WORD = "edit";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) "
- + "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
-
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
- public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
-
- private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
-
- /**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
- */
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
- requireNonNull(index);
- requireNonNull(editPersonDescriptor);
-
- this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
- }
-
@Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
-
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
- }
-
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- 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());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
+ public abstract CommandResult execute(Model model) throws CommandException;
@Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditCommand)) {
- return false;
- }
-
- // state check
- EditCommand e = (EditCommand) other;
- return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
- }
-
- /**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
- */
- public static class EditPersonDescriptor {
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- public EditPersonDescriptor() {}
-
- /**
- * Copy constructor.
- * A defensive copy of {@code tags} is used internally.
- */
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
- setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
- }
-
- /**
- * Returns true if at least one field is edited.
- */
- public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public Optional getName() {
- return Optional.ofNullable(name);
- }
-
- public void setPhone(Phone phone) {
- this.phone = phone;
- }
-
- public Optional getPhone() {
- return Optional.ofNullable(phone);
- }
-
- public void setEmail(Email email) {
- this.email = email;
- }
-
- public Optional getEmail() {
- return Optional.ofNullable(email);
- }
-
- public void setAddress(Address address) {
- this.address = address;
- }
-
- public Optional getAddress() {
- return Optional.ofNullable(address);
- }
-
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
- }
-
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
- return false;
- }
-
- // state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
-
- return getName().equals(e.getName())
- && getPhone().equals(e.getPhone())
- && getEmail().equals(e.getEmail())
- && getAddress().equals(e.getAddress())
- && getTags().equals(e.getTags());
- }
- }
+ public abstract boolean equals(Object other);
}
diff --git a/src/main/java/seedu/address/logic/commands/EditInterviewCommand.java b/src/main/java/seedu/address/logic/commands/EditInterviewCommand.java
new file mode 100644
index 00000000000..1ac737b10f7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditInterviewCommand.java
@@ -0,0 +1,172 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_INTERVIEWS;
+
+import java.util.List;
+import java.util.Optional;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Date;
+import seedu.address.model.Model;
+import seedu.address.model.Time;
+import seedu.address.model.interview.Interview;
+
+public class EditInterviewCommand extends EditCommand {
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [i] : Edits the details of the interview identified "
+ + "by the index number used in the displayed interview list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "<" + PREFIX_DATE + "DATE> "
+ + "<" + PREFIX_TIME + "TIME> \n"
+ + "Example: " + COMMAND_WORD + " [i] 1 "
+ + PREFIX_DATE + "2021-05-06 "
+ + PREFIX_TIME + "10:30";
+
+ public static final String MESSAGE_EDIT_INTERVIEW_SUCCESS = "Edited Interview: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_INTERVIEW = "This interview already exists in the address book.";
+
+ private final Index index;
+ private final EditInterviewDescriptor editInterviewDescriptor;
+
+ /**
+ * @param index of the interview in the filtered interview list to edit
+ * @param editInterviewDescriptor details to edit the interview with
+ */
+ public EditInterviewCommand(Index index, EditInterviewDescriptor editInterviewDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editInterviewDescriptor);
+
+ this.index = index;
+ this.editInterviewDescriptor = new EditInterviewDescriptor(editInterviewDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInterviewList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_INTERVIEW_DISPLAYED_INDEX);
+ }
+
+ Interview interviewToEdit = lastShownList.get(index.getZeroBased());
+
+ Interview editedInterview = createEditedInterview(interviewToEdit, editInterviewDescriptor);
+
+ if (!interviewToEdit.isSameInterview(editedInterview) && model.hasInterview(editedInterview)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERVIEW);
+ }
+
+ model.setInterview(interviewToEdit, editedInterview);
+ model.updateFilteredInterviewList(PREDICATE_SHOW_ALL_INTERVIEWS);
+ return new CommandResult(String.format(MESSAGE_EDIT_INTERVIEW_SUCCESS, editedInterview), getType());
+ }
+
+ /**
+ * Creates and returns a {@code Interview} with the details of {@code interviewToEdit}
+ * edited with {@code editInterviewDescriptor}.
+ */
+ private static Interview createEditedInterview(
+ Interview interviewToEdit, EditInterviewDescriptor editInterviewDescriptor) {
+ assert interviewToEdit != null;
+
+ Date updatedDate = editInterviewDescriptor.getDate().orElse(interviewToEdit.getDate());
+ Time updatedTime = editInterviewDescriptor.getTime().orElse(interviewToEdit.getTime());
+
+ return new Interview(interviewToEdit.getPerson(), updatedDate, updatedTime);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditInterviewCommand)) {
+ return false;
+ }
+
+ // state check
+ EditInterviewCommand e = (EditInterviewCommand) other;
+ return index.equals(e.index)
+ && editInterviewDescriptor.equals(e.editInterviewDescriptor);
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+ /**
+ * Stores the details to edit the interview with. Each non-empty field value will replace the
+ * corresponding field value of the interview.
+ */
+ public static class EditInterviewDescriptor {
+ private Date date;
+ private Time time;
+
+ public EditInterviewDescriptor() {}
+
+ /**
+ * Copy constructor.
+ *
+ */
+ public EditInterviewDescriptor(EditInterviewDescriptor toCopy) {
+ setDate(toCopy.date);
+ setTime(toCopy.time);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(date, time);
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public Optional getDate() {
+ return Optional.ofNullable(date);
+ }
+
+ public void setTime(Time time) {
+ this.time = time;
+ }
+
+ public Optional getTime() {
+ return Optional.ofNullable(time);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditInterviewDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditInterviewDescriptor e = (EditInterviewDescriptor) other;
+
+ return getDate().equals(e.getDate())
+ && getTime().equals(e.getTime());
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditPersonCommand.java b/src/main/java/seedu/address/logic/commands/EditPersonCommand.java
new file mode 100644
index 00000000000..930a3b39f19
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditPersonCommand.java
@@ -0,0 +1,256 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_PERSON_HAS_INTERVIEW;
+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_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.Type.PERSON;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.List;
+import java.util.Optional;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Stage;
+
+/**
+ * Edits the details of an existing applicant in the address book.
+*/
+public class EditPersonCommand extends EditCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [p] : Edits the details of the applicant identified "
+ + "by the index number used in the displayed applicant list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "<" + PREFIX_NAME + "NAME> "
+ + "<" + PREFIX_PHONE + "PHONE> "
+ + "<" + PREFIX_EMAIL + "EMAIL> "
+ + "<" + PREFIX_ADDRESS + "ADDRESS> "
+ + "<" + PREFIX_JOB + "JOB> "
+ + "<" + PREFIX_STAGE + "STAGE> \n"
+ + "Example: " + COMMAND_WORD + " [p] 1 "
+ + PREFIX_PHONE + "91234567 "
+ + PREFIX_EMAIL + "johndoe@example.com";
+
+ public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Applicant: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_PERSON = "This applicant already exists in the address book.";
+
+ private final Index index;
+ private final EditPersonDescriptor editPersonDescriptor;
+
+ /**
+ * @param index of the applicant in the filtered applicant list to edit
+ * @param editPersonDescriptor details to edit the applicant with
+ */
+ public EditPersonCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editPersonDescriptor);
+
+ this.index = index;
+ this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(index.getZeroBased());
+ Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+
+ if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ }
+ if (personHasInterview(personToEdit, model)) {
+ throw new CommandException(MESSAGE_PERSON_HAS_INTERVIEW);
+ }
+
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson), getType());
+ }
+
+ /**
+ * Check if applicant that we wish to edit has interview
+ *
+ * @param person applicant
+ * @param model model
+ * @return true if applicant has interview
+ */
+ public boolean personHasInterview(Person person, Model model) {
+ List lastShownInterviewList = model.getFilteredInterviewList();
+ for (int i = 0; i < lastShownInterviewList.size(); i++) {
+ if (lastShownInterviewList.get(i).getPerson().equals(person)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates and returns a {@code Person} with the details of {@code personToEdit}
+ * edited with {@code editPersonDescriptor}.
+ */
+ private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
+ assert personToEdit != null;
+
+ 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());
+ Job updatedJob = editPersonDescriptor.getJob().orElse(personToEdit.getJob());
+ Stage updatedStage = editPersonDescriptor.getStage().orElse(personToEdit.getStage());
+
+ return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedJob, updatedStage);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditPersonCommand)) {
+ return false;
+ }
+
+ // state check
+ EditPersonCommand e = (EditPersonCommand) other;
+ return index.equals(e.index)
+ && editPersonDescriptor.equals(e.editPersonDescriptor);
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+
+ /**
+ * Stores the details to edit the applicant with. Each non-empty field value will replace the
+ * corresponding field value of the applicant.
+ */
+ public static class EditPersonDescriptor {
+ private Name name;
+ private Phone phone;
+ private Email email;
+ private Address address;
+ private Job job;
+ private Stage stage;
+
+ public EditPersonDescriptor() {}
+
+ /**
+ * Copy constructor.
+ */
+ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
+ setName(toCopy.name);
+ setPhone(toCopy.phone);
+ setEmail(toCopy.email);
+ setAddress(toCopy.address);
+ setJob(toCopy.job);
+ setStage(toCopy.stage);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(name, phone, email, address, job, stage);
+ }
+
+ public void setName(Name name) {
+ this.name = name;
+ }
+
+ public Optional getName() {
+ return Optional.ofNullable(name);
+ }
+
+ public void setPhone(Phone phone) {
+ this.phone = phone;
+ }
+
+ public Optional getPhone() {
+ return Optional.ofNullable(phone);
+ }
+
+ public void setEmail(Email email) {
+ this.email = email;
+ }
+
+ public Optional getEmail() {
+ return Optional.ofNullable(email);
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ public Optional getAddress() {
+ return Optional.ofNullable(address);
+ }
+
+ public void setJob(Job job) {
+ this.job = job;
+ }
+
+ public Optional getJob() {
+ return Optional.ofNullable(job);
+ }
+
+ public void setStage(Stage stage) {
+ this.stage = stage;
+ }
+
+ public Optional getStage() {
+ return Optional.ofNullable(stage);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditPersonDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditPersonDescriptor e = (EditPersonDescriptor) other;
+
+ return getName().equals(e.getName())
+ && getPhone().equals(e.getPhone())
+ && getEmail().equals(e.getEmail())
+ && getAddress().equals(e.getAddress())
+ && getJob().equals(e.getJob())
+ && getStage().equals(e.getStage());
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/EditTaskCommand.java b/src/main/java/seedu/address/logic/commands/EditTaskCommand.java
new file mode 100644
index 00000000000..afa59718083
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditTaskCommand.java
@@ -0,0 +1,204 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+import static seedu.address.logic.parser.Type.TASK;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import java.util.List;
+import java.util.Optional;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Date;
+import seedu.address.model.Model;
+import seedu.address.model.Time;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
+import seedu.address.model.tasks.Task;
+
+public class EditTaskCommand extends EditCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [t] : Edits the details of the task identified "
+ + "by the index number used in the displayed task list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "<" + PREFIX_HEADER + "HEADER> "
+ + "<" + PREFIX_DATE + "DATE> "
+ + "<" + PREFIX_TIME + "TIME> "
+ + "<" + PREFIX_INFORMATION + "INFORMATION> \n"
+ + "Example: " + COMMAND_WORD + " [t] 1 "
+ + PREFIX_HEADER + "Update interview statuses "
+ + PREFIX_DATE + "2021-05-06 ";
+
+ public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the address book.";
+
+ private final Index index;
+ private final EditTaskDescriptor editTaskDescriptor;
+
+ /**
+ * @param index of the task in the filtered task list to edit
+ * @param editTaskDescriptor details to edit the task with
+ */
+ public EditTaskCommand(Index index, EditTaskDescriptor editTaskDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editTaskDescriptor);
+
+ this.index = index;
+ this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredTaskList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ Task taskToEdit = lastShownList.get(index.getZeroBased());
+
+ Task editedTask = createEditedTask(taskToEdit, editTaskDescriptor);
+
+ if (!taskToEdit.isSameTask(editedTask) && model.hasTask(editedTask)) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ }
+
+ model.setTask(taskToEdit, editedTask);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, editedTask), getType());
+ }
+
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToEdit}
+ * edited with {@code editTaskDescriptor}.
+ */
+ private static Task createEditedTask(
+ Task taskToEdit, EditTaskDescriptor editTaskDescriptor) {
+ assert taskToEdit != null;
+
+ Header updatedHeader = editTaskDescriptor.getHeader().orElse(taskToEdit.getHeader());
+ Information updatedInformation = editTaskDescriptor.getInformation().orElse(taskToEdit.getInformation());
+ Date updatedDate = editTaskDescriptor.getDate().orElse(taskToEdit.getDate());
+ Time updatedTime = editTaskDescriptor.getTime().orElse(taskToEdit.getTime());
+
+ return new Task(updatedHeader, updatedDate, updatedTime, updatedInformation);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditTaskCommand)) {
+ return false;
+ }
+
+ // state check
+ EditTaskCommand e = (EditTaskCommand) other;
+ return index.equals(e.index)
+ && editTaskDescriptor.equals(e.editTaskDescriptor);
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+
+ /**
+ * Stores the details to edit the task with. Each non-empty field value will replace the
+ * corresponding field value of the task.
+ */
+ public static class EditTaskDescriptor {
+ private Header header;
+ private Information information;
+ private Date date;
+ private Time time;
+
+ public EditTaskDescriptor() {}
+
+ /**
+ * Copy constructor.
+ *
+ */
+ public EditTaskDescriptor(EditTaskDescriptor toCopy) {
+ setHeader(toCopy.header);
+ setInformation(toCopy.information);
+ setDate(toCopy.date);
+ setTime(toCopy.time);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(header, information, date, time);
+ }
+
+ public void setHeader(Header header) {
+ this.header = header;
+ }
+
+ public Optional getHeader() {
+ return Optional.ofNullable(header);
+ }
+
+ public void setInformation(Information information) {
+ this.information = information;
+ }
+
+ public Optional getInformation() {
+ return Optional.ofNullable(information);
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public Optional getDate() {
+ return Optional.ofNullable(date);
+ }
+
+ public void setTime(Time time) {
+ this.time = time;
+ }
+
+ public Optional getTime() {
+ return Optional.ofNullable(time);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditTaskDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditTaskDescriptor e = (EditTaskDescriptor) other;
+
+ return getHeader().equals(e.getHeader())
+ && getInformation().equals(e.getInformation())
+ && getDate().equals(e.getDate())
+ && getTime().equals(e.getTime());
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..a8c83dbb04f 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -9,11 +9,11 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting HRConnect as requested ...";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, getType(), false, true);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ExportCommand.java b/src/main/java/seedu/address/logic/commands/ExportCommand.java
new file mode 100644
index 00000000000..bb704770655
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ExportCommand.java
@@ -0,0 +1,67 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.util.FileUtil;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+
+public class ExportCommand extends Command {
+ public static final String COMMAND_WORD = "export";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Exports all data of the all applicants into a CSV file. Accepts absolute path or relative path.\n"
+ + "Parameters: filepath to the exported csv file\n"
+ + "Example: export ../../myDataFile.csv";
+ public static final String MISSING_CSV_FILE = "CSV file could not be created.";
+
+ private final Path csvFilePath;
+
+ /**
+ * Constructor for Export Command.
+ *
+ * @param csvFilePath File path of CSV file to export applicant data to.
+ */
+ public ExportCommand(Path csvFilePath) {
+ requireNonNull(csvFilePath);
+ this.csvFilePath = csvFilePath;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ ObservableList personList = model.getFilteredPersonList(); //to read from json and write to CSV
+
+ try {
+ //create new csv file to export data into
+ FileUtil.createFile(csvFilePath);
+ PrintWriter pw = new PrintWriter(csvFilePath.toString());
+ for (Person p : personList) {
+ String name = p.getName().toString();
+ String phone = p.getPhone().toString();
+ String email = p.getEmail().toString();
+ String address = p.getAddress().toString();
+ String job = p.getJob().toString();
+ String stage = p.getStage().toString();
+ pw.printf("%s\t%s\t%s\t%s\t%s\t%s\n", name, phone, email, address, job, stage);
+ }
+ pw.close();
+ } catch (IOException e) {
+ throw new CommandException(MISSING_CSV_FILE);
+ }
+ return new CommandResult("Exported " + personList.size() + " applicants' data to "
+ + csvFilePath, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index d6b19b0a0de..91457c5e027 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -1,42 +1,17 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
/**
- * 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 data in the address book which satisfies the search criteria.
*/
-public class FindCommand extends Command {
+public abstract 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"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
-
- private final NameContainsKeywordsPredicate predicate;
-
- public FindCommand(NameContainsKeywordsPredicate 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()));
- }
+ public abstract CommandResult execute(Model model);
@Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof FindCommand // instanceof handles nulls
- && predicate.equals(((FindCommand) other).predicate)); // state check
- }
+ public abstract boolean equals(Object other);
}
diff --git a/src/main/java/seedu/address/logic/commands/FindInterviewCommand.java b/src/main/java/seedu/address/logic/commands/FindInterviewCommand.java
new file mode 100644
index 00000000000..96a61396b75
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindInterviewCommand.java
@@ -0,0 +1,60 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.interview.InterviewContainsKeywordsPredicate;
+
+public class FindInterviewCommand extends FindCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [i] : Finds all interviews that meet search criteria.\n"
+ + "Only accepts: g/, d/, t/, n/ and j/ flags\n"
+ + "Example: " + COMMAND_WORD + " [i] g/n/john j/software engineer g/d/2021-05-06";
+
+ private InterviewContainsKeywordsPredicate predicate;
+
+ /**
+ * Constructor for FindInterviewCommand
+ *
+ * @param predicate Search criteria to find interviews
+ */
+
+ public FindInterviewCommand(InterviewContainsKeywordsPredicate predicate) {
+ requireNonNull(predicate);
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInterviewList(predicate);
+ return new CommandResult(String.format(Messages.MESSAGE_INTERVIEWS_LISTED_OVERVIEW,
+ model.getFilteredInterviewList().size()), getType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindInterviewCommand)) {
+ return false;
+ }
+
+ // state check
+ FindInterviewCommand e = (FindInterviewCommand) other;
+ return predicate.equals(e.predicate);
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindPersonCommand.java b/src/main/java/seedu/address/logic/commands/FindPersonCommand.java
new file mode 100644
index 00000000000..a246fcefee9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindPersonCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
+
+public class FindPersonCommand extends FindCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [p] : Finds all applicants that meet search criteria.\n"
+ + "Only accepts: g/, n/, p/, e/, a/, j/, and s/ flags\n"
+ + "Example: " + COMMAND_WORD + " [p] g/n/john j/software engineer g/s/INPROGRESS";
+
+ private PersonContainsKeywordsPredicate predicate;
+
+ /**
+ * Constructor for FindPersonCommand
+ *
+ * @param predicate Search criteria to find applicants
+ */
+ public FindPersonCommand(PersonContainsKeywordsPredicate predicate) {
+ requireNonNull(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()), getType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindPersonCommand)) {
+ return false;
+ }
+
+ // state check
+ FindPersonCommand e = (FindPersonCommand) other;
+ return predicate.equals(e.predicate);
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindTaskCommand.java b/src/main/java/seedu/address/logic/commands/FindTaskCommand.java
new file mode 100644
index 00000000000..e73b7648eba
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindTaskCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.TASK;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.tasks.TaskContainsKeywordPredicate;
+
+public class FindTaskCommand extends FindCommand {
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " [t] : Finds all tasks that meet search criteria.\n"
+ + "Only accepts: g/, h/, d/, t/, and i/ flags\n"
+ + "Example: " + COMMAND_WORD + " [t] g/h/update d/2022-01-19 g/i/add";
+
+ private TaskContainsKeywordPredicate predicate;
+
+ /**
+ * Constructor for FindTaskCommand
+ *
+ * @param predicate Search criteria to find tasks
+ */
+ public FindTaskCommand(TaskContainsKeywordPredicate predicate) {
+ requireNonNull(predicate);
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredTaskList(predicate);
+ return new CommandResult(String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW,
+ model.getFilteredTaskList().size()), getType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindTaskCommand)) {
+ return false;
+ }
+
+ // state check
+ FindTaskCommand e = (FindTaskCommand) other;
+ return predicate.equals(e.predicate);
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..1257cef82ce 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, getType(), true, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ImportCommand.java b/src/main/java/seedu/address/logic/commands/ImportCommand.java
new file mode 100644
index 00000000000..49ce12112a5
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ImportCommand.java
@@ -0,0 +1,78 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.PERSON;
+
+import java.util.List;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+
+public class ImportCommand extends Command {
+
+ public static final String COMMAND_WORD = "import";
+ public static final String MESSAGE_USAGE =
+ "Imports all job applicants data from csv file. Accepts absolute or relative path.\n"
+ + "The csv file needs to contain the same fields as the 'add [p]' command.\n"
+ + "Parameters: filepath to csv file\n"
+ + "Example: import ../../past_data.csv";
+
+ private List persons;
+
+ /**
+ * Constructor for Import Command.
+ *
+ * @param persons List of applicants to be added.
+ */
+ public ImportCommand(List persons) {
+ requireNonNull(persons);
+ this.persons = persons;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // checks if any persons is already in address book.
+ for (int i = 0; i < persons.size(); i++) {
+ if (model.hasPerson(persons.get(i))) {
+ int entryNum = i + 1;
+ throw new CommandException("Entry " + entryNum + " is already in address book.\nAborting now.");
+ }
+ }
+
+ persons.forEach(model::addPerson);
+ return new CommandResult("Added " + persons.size() + " applicants to address book.", getType());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ persons.forEach(person -> s.append(person.toString() + "\n"));
+ return s.toString().strip();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ImportCommand)) {
+ return false;
+ }
+
+ // state check
+ ImportCommand e = (ImportCommand) other;
+ return this.toString().equals(e.toString());
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..c267ea823b6 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,24 +1,13 @@
package seedu.address.logic.commands;
-import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
import seedu.address.model.Model;
-/**
- * Lists all persons in the address book to the user.
- */
-public class ListCommand extends Command {
+public abstract class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
-
- public static final String MESSAGE_SUCCESS = "Listed all persons";
-
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " [p] to list all applicants"
+ + " or [i] to list all interviews" + " or [t] to list all tasks";
@Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
- }
+ public abstract CommandResult execute(Model model);
}
diff --git a/src/main/java/seedu/address/logic/commands/ListInterviewCommand.java b/src/main/java/seedu/address/logic/commands/ListInterviewCommand.java
new file mode 100644
index 00000000000..14016068118
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListInterviewCommand.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_INTERVIEWS;
+
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ListInterviewCommand extends ListCommand {
+ public static final String MESSAGE_SUCCESS = "Listed all interviews!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInterviewList(PREDICATE_SHOW_ALL_INTERVIEWS);
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return INTERVIEW;
+ }
+}
+
+
diff --git a/src/main/java/seedu/address/logic/commands/ListPersonCommand.java b/src/main/java/seedu/address/logic/commands/ListPersonCommand.java
new file mode 100644
index 00000000000..d3a5a070e52
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListPersonCommand.java
@@ -0,0 +1,24 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.PERSON;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ListPersonCommand extends ListCommand {
+ public static final String MESSAGE_SUCCESS = "Listed all applicants!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return PERSON;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListTaskCommand.java b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java
new file mode 100644
index 00000000000..01f43c6cd00
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListTaskCommand.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.Type.TASK;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import seedu.address.logic.parser.Type;
+import seedu.address.model.Model;
+
+public class ListTaskCommand extends ListCommand {
+ public static final String MESSAGE_SUCCESS = "Listed all tasks!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ return new CommandResult(MESSAGE_SUCCESS, getType());
+ }
+
+ @Override
+ public Type getType() {
+ return TASK;
+ }
+}
+
+
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..6bbafa1e58d 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
@@ -1,7 +1,7 @@
package seedu.address.logic.commands.exceptions;
/**
- * Represents an error which occurs during execution of a {@link Command}.
+ * Represents an error which occurs during execution of a {@link String}.
*/
public class CommandException extends Exception {
public CommandException(String message) {
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 3b8bfa035e8..c8d61f26569 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -1,23 +1,11 @@
package seedu.address.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-import java.util.stream.Stream;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
/**
* Parses input arguments and creates a new AddCommand object
@@ -27,34 +15,22 @@ public class AddCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the AddCommand
* and returns an AddCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ String type = ArgumentTokenizer.getType(args.trim());
+ String removedType = args.trim().substring(3);
+
+ switch (type) {
+ case TYPE_PERSON:
+ return new AddPersonCommandParser().parse(removedType);
+ case TYPE_INTERVIEW:
+ return new AddInterviewCommandParser().parse(removedType);
+ case TYPE_TASK:
+ return new AddTaskCommandParser().parse(removedType);
+ default:
+ return null;
}
-
- 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());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
}
-
- /**
- * 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/AddInterviewCommandParser.java b/src/main/java/seedu/address/logic/parser/AddInterviewCommandParser.java
new file mode 100644
index 00000000000..41153559fbe
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddInterviewCommandParser.java
@@ -0,0 +1,56 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddInterviewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+
+/**
+ * Parses input arguments and creates a new AddInterviewCommand object
+ */
+public class AddInterviewCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddInterviewCommand
+ * and returns an AddInterviewCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddInterviewCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_DATE, PREFIX_TIME);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddInterviewCommand.MESSAGE_USAGE), pe);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_DATE, PREFIX_TIME)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddInterviewCommand.MESSAGE_USAGE));
+ }
+
+ Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());
+ Time time = ParserUtil.parseTime(argMultimap.getValue(PREFIX_TIME).get());
+
+ return new AddInterviewCommand(index, date, time);
+ }
+
+ /**
+ * 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/AddPersonCommandParser.java b/src/main/java/seedu/address/logic/parser/AddPersonCommandParser.java
new file mode 100644
index 00000000000..b834bcdfbb1
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddPersonCommandParser.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+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_JOB;
+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_STAGE;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddPersonCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Stage;
+
+
+/**
+ * Parses input arguments and creates a new AddPersonCommand object
+ */
+public class AddPersonCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddPersonCommand
+ * and returns an AddPersonCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddPersonCommand parse(String args) throws ParseException {
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_JOB, PREFIX_STAGE) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddPersonCommand.MESSAGE_USAGE));
+ }
+
+ 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());
+ Job job = ParserUtil.parseJob(argMultimap.getValue(PREFIX_JOB).get());
+ Stage stage = ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get());
+
+ Person person = new Person(name, phone, email, address, job, stage);
+
+ return new AddPersonCommand(person);
+ }
+
+ /**
+ * 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/AddTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/AddTaskCommandParser.java
new file mode 100644
index 00000000000..136f31f8bd2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddTaskCommandParser.java
@@ -0,0 +1,57 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
+import seedu.address.model.tasks.Task;
+
+/**
+ * Parses input arguments and creates a new AddTaskCommand object
+ */
+public class AddTaskCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddTaskCommand
+ * and returns an AddTaskCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddTaskCommand parse(String args) throws ParseException {
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_HEADER, PREFIX_INFORMATION, PREFIX_DATE, PREFIX_TIME);
+
+ if (!arePrefixesPresent(argMultimap,
+ PREFIX_HEADER, PREFIX_INFORMATION, PREFIX_DATE, PREFIX_TIME) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTaskCommand.MESSAGE_USAGE));
+ }
+ Header header = ParserUtil.parseHeader(argMultimap.getValue(PREFIX_HEADER).get());
+ Information information = ParserUtil.parseInformation(argMultimap.getValue(PREFIX_INFORMATION).get());
+ Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());
+ Time time = ParserUtil.parseTime(argMultimap.getValue(PREFIX_TIME).get());
+
+ Task newTask = new Task(header, date, time, information);
+
+ return new AddTaskCommand(newTask);
+ }
+
+ /**
+ * 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 1e466792b46..68494ef9aad 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -12,8 +12,10 @@
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.ExportCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ImportCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.parser.exceptions.ParseException;
@@ -47,20 +49,17 @@ public Command parseCommand(String userInput) throws ParseException {
case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
case DeleteCommand.COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);
case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
+ return new ClearCommandParser().parse(arguments);
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
case ListCommand.COMMAND_WORD:
- return new ListCommand();
+ return new ListCommandParser().parse(arguments);
case ExitCommand.COMMAND_WORD:
return new ExitCommand();
@@ -68,9 +67,17 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments);
+
+ case ImportCommand.COMMAND_WORD:
+ return new ImportCommandParser().parse(arguments);
+
+ case ExportCommand.COMMAND_WORD:
+ return new ExportCommandParser().parse(arguments);
+
default:
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 954c8e18f8e..83ec7e585aa 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
@@ -36,7 +36,9 @@ public void put(Prefix prefix, String argValue) {
*/
public Optional getValue(Prefix prefix) {
List values = getAllValues(prefix);
- return values.isEmpty() ? Optional.empty() : Optional.of(values.get(values.size() - 1));
+ return values.isEmpty()
+ ? Optional.empty()
+ : Optional.of(values.get(values.size() - 1));
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..6f1e4475aa1 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
@@ -1,10 +1,15 @@
package seedu.address.logic.parser;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_TYPE_GIVEN;
+import static seedu.address.commons.core.Messages.MESSAGE_NO_TYPE_GIVEN;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
+import seedu.address.logic.parser.exceptions.ParseException;
+
/**
* Tokenizes arguments string of the form: {@code preamble value value ...}
* e.g. {@code some preamble text t/ 11.00 t/12.00 k/ m/ July} where prefixes are {@code t/ k/ m/}.
@@ -145,4 +150,17 @@ Prefix getPrefix() {
}
}
+ public static String getType(String trimmedArgsString) throws ParseException {
+ if (trimmedArgsString.equals("") || trimmedArgsString.length() < 3) {
+ throw new ParseException(MESSAGE_NO_TYPE_GIVEN);
+ } else if (trimmedArgsString.charAt(0) != '[' || trimmedArgsString.charAt(2) != ']') {
+ throw new ParseException(MESSAGE_INVALID_TYPE_GIVEN);
+ } else if (trimmedArgsString.charAt(1) != 'p' && trimmedArgsString.charAt(1) != 'i'
+ && trimmedArgsString.charAt(1) != 't') {
+ throw new ParseException(MESSAGE_INVALID_TYPE_GIVEN);
+ }
+
+ return trimmedArgsString.substring(0, 3);
+ }
+
}
diff --git a/src/main/java/seedu/address/logic/parser/ClearCommandParser.java b/src/main/java/seedu/address/logic/parser/ClearCommandParser.java
new file mode 100644
index 00000000000..b21980a7944
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ClearCommandParser.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
+
+import seedu.address.logic.commands.ClearCommand;
+import seedu.address.logic.commands.ClearInterviewCommand;
+import seedu.address.logic.commands.ClearPersonCommand;
+import seedu.address.logic.commands.ClearTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class ClearCommandParser {
+ /**
+ * Parse ClearCommand
+ */
+ public ClearCommand parse(String args) throws ParseException {
+ String type = ArgumentTokenizer.getType(args.trim());
+ String removedType = args.trim().substring(3);
+
+ if (removedType.length() != 0) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ClearCommand.MESSAGE_USAGE));
+ }
+
+ switch (type) {
+ case TYPE_PERSON:
+ return new ClearPersonCommand();
+ case TYPE_INTERVIEW:
+ return new ClearInterviewCommand();
+ case TYPE_TASK:
+ return new ClearTaskCommand();
+ default:
+ return null;
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..12e33db52d6 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -10,6 +10,16 @@ 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_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_JOB = new Prefix("j/");
+ public static final Prefix PREFIX_STAGE = new Prefix("s/");
+ public static final Prefix PREFIX_DATE = new Prefix("d/");
+ public static final Prefix PREFIX_TIME = new Prefix("t/");
+ public static final Prefix PREFIX_GROUP = new Prefix("g/");
+ public static final Prefix PREFIX_HEADER = new Prefix("h/");
+ public static final Prefix PREFIX_INFORMATION = new Prefix("i/");
+ /* Type definitions */
+ public static final String TYPE_INTERVIEW = "[i]";
+ public static final String TYPE_PERSON = "[p]";
+ public static final String TYPE_TASK = "[t]";
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 522b93081cc..a8faf8a44ad 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -1,8 +1,9 @@
package seedu.address.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.parser.exceptions.ParseException;
@@ -12,18 +13,24 @@
public class DeleteCommandParser implements Parser {
/**
- * Parses the given {@code String} of arguments in the context of the DeleteCommand
- * and returns a DeleteCommand object for execution.
+ * Parses the given {@code String} of arguments in the context of the
+ * DeleteCommand and returns a DeleteCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public DeleteCommand parse(String args) throws ParseException {
- try {
- Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
- } catch (ParseException pe) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ String type = ArgumentTokenizer.getType(args.trim());
+ String removedType = args.trim().substring(3);
+
+ switch (type) {
+ case TYPE_PERSON:
+ return new DeletePersonCommandParser().parse(removedType);
+ case TYPE_INTERVIEW:
+ return new DeleteInterviewCommandParser().parse(removedType);
+ case TYPE_TASK:
+ return new DeleteTaskCommandParser().parse(removedType);
+ default:
+ return null;
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteInterviewCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteInterviewCommandParser.java
new file mode 100644
index 00000000000..931ce9832fa
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteInterviewCommandParser.java
@@ -0,0 +1,30 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteInterviewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class DeleteInterviewCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteInterviewCommand
+ * and returns a DeleteInterviewCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteInterviewCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteInterviewCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteInterviewCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
+
+
+
+
diff --git a/src/main/java/seedu/address/logic/parser/DeletePersonCommandParser.java b/src/main/java/seedu/address/logic/parser/DeletePersonCommandParser.java
new file mode 100644
index 00000000000..e8d58339982
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeletePersonCommandParser.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeletePersonCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class DeletePersonCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeletePersonCommand
+ * and returns a DeletePersonCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeletePersonCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeletePersonCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeletePersonCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java
new file mode 100644
index 00000000000..af8ef25ef78
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteTaskCommandParser.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class DeleteTaskCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the
+ * DeleteTaskCommand and returns a DeleteTaskCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteTaskCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteTaskCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTaskCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 845644b7dea..ec0c5bbafeb 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -1,23 +1,11 @@
package seedu.address.logic.parser;
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
/**
* Parses input arguments and creates a new EditCommand object
@@ -25,58 +13,26 @@
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.
+ * Parses the given {@code String} of arguments in the context of the
+ * EditCommand and returns a 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);
-
- Index index;
-
- try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
- }
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
- }
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
- }
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ String type = ArgumentTokenizer.getType(args.trim());
+ String removedType = args.trim().substring(3);
+
+ switch (type) {
+ case TYPE_PERSON:
+ return new EditPersonCommandParser().parse(removedType);
+ case TYPE_INTERVIEW:
+ return new EditInterviewCommandParser().parse(removedType);
+ case TYPE_TASK:
+ return new EditTaskCommandParser().parse(removedType);
+ default:
+ return null;
}
-
- 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
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
}
}
+
diff --git a/src/main/java/seedu/address/logic/parser/EditInterviewCommandParser.java b/src/main/java/seedu/address/logic/parser/EditInterviewCommandParser.java
new file mode 100644
index 00000000000..c26d554c2bd
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditInterviewCommandParser.java
@@ -0,0 +1,48 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditInterviewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class EditInterviewCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditInterviewCommand
+ * and returns an EditInterviewCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditInterviewCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_DATE, PREFIX_TIME);
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditInterviewCommand.MESSAGE_USAGE), pe);
+ }
+
+ EditInterviewCommand.EditInterviewDescriptor editInterviewDescriptor =
+ new EditInterviewCommand.EditInterviewDescriptor();
+ if (argMultimap.getValue(PREFIX_DATE).isPresent()) {
+ editInterviewDescriptor.setDate(ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_TIME).isPresent()) {
+ editInterviewDescriptor.setTime(ParserUtil.parseTime(argMultimap.getValue(PREFIX_TIME).get()));
+ }
+
+ if (!editInterviewDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditInterviewCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditInterviewCommand(index, editInterviewDescriptor);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditPersonCommandParser.java b/src/main/java/seedu/address/logic/parser/EditPersonCommandParser.java
new file mode 100644
index 00000000000..f17dda198ea
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditPersonCommandParser.java
@@ -0,0 +1,64 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+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_JOB;
+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_STAGE;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditPersonCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class EditPersonCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditPersonCommand
+ * and returns an EditPersonCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditPersonCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE);
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditPersonCommand.MESSAGE_USAGE), pe);
+ }
+
+ EditPersonCommand.EditPersonDescriptor editPersonDescriptor = new EditPersonCommand.EditPersonDescriptor();
+ if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ }
+ if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
+ editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ }
+ if (argMultimap.getValue(PREFIX_JOB).isPresent()) {
+ editPersonDescriptor.setJob(ParserUtil.parseJob(argMultimap.getValue(PREFIX_JOB).get()));
+ }
+ if (argMultimap.getValue(PREFIX_STAGE).isPresent()) {
+ editPersonDescriptor.setStage(ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get()));
+ }
+
+ if (!editPersonDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditPersonCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditPersonCommand(index, editPersonDescriptor);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/EditTaskCommandParser.java
new file mode 100644
index 00000000000..1563182521b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditTaskCommandParser.java
@@ -0,0 +1,58 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class EditTaskCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditTaskCommand
+ * and returns an EditTaskCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditTaskCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_HEADER, PREFIX_INFORMATION, PREFIX_DATE, PREFIX_TIME);
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditTaskCommand.MESSAGE_USAGE), pe);
+ }
+
+ EditTaskCommand.EditTaskDescriptor editTaskDescriptor =
+ new EditTaskCommand.EditTaskDescriptor();
+ if (argMultimap.getValue(PREFIX_HEADER).isPresent()) {
+ editTaskDescriptor.setHeader(ParserUtil.parseHeader(
+ argMultimap.getValue(PREFIX_HEADER).get()));
+ }
+ if (argMultimap.getValue(PREFIX_INFORMATION).isPresent()) {
+ editTaskDescriptor.setInformation(ParserUtil.parseInformation(
+ argMultimap.getValue(PREFIX_INFORMATION).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DATE).isPresent()) {
+ editTaskDescriptor.setDate(ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_TIME).isPresent()) {
+ editTaskDescriptor.setTime(ParserUtil.parseTime(argMultimap.getValue(PREFIX_TIME).get()));
+ }
+ if (!editTaskDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditTaskCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditTaskCommand(index, editTaskDescriptor);
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/ExportCommandParser.java b/src/main/java/seedu/address/logic/parser/ExportCommandParser.java
new file mode 100644
index 00000000000..58018125eb1
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ExportCommandParser.java
@@ -0,0 +1,58 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.util.FileUtil.isValidPath;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import seedu.address.logic.commands.ExportCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class ExportCommandParser implements Parser {
+ public static final String INVALID_FILE_NAME = "File name should only contain alphanumeric characters";
+ public static final String INVALID_FILE_PATH = "That is not a valid file path\n" + INVALID_FILE_NAME;
+ public static final String WRONG_FILE_TYPE = "Please include a .csv file extension with your file name.";
+
+ /**
+ * Parses the user input of the path to target csv file to export applicant data into.
+ *
+ * @param args String path to the csv file.
+ * @return ExportCommand with path to csv file.
+ */
+ public ExportCommand parse(String args) throws ParseException {
+
+ //check whether valid path input given by the user
+ String strCsvFilePath = args.strip();
+ checkFilePath(strCsvFilePath);
+ Path csvFilePath = Paths.get(strCsvFilePath);
+
+ return new ExportCommand(csvFilePath);
+ }
+
+ /**
+ * Checks if specified filepath to csv file is not empty string and a valid csv filepath.
+ *
+ * @param path filepath to target csv file.
+ * @throws ParseException If filepath is "" or not a valid filepath or not a .csv file.
+ */
+ private void checkFilePath(String path) throws ParseException {
+ if (path.equals("")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ExportCommand.MESSAGE_USAGE));
+ } else if (!isValidPath(path)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, INVALID_FILE_PATH));
+ } else if (!isValidCsvFile(path)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, WRONG_FILE_TYPE));
+ }
+ }
+
+ /**
+ * Checks if the given file path leads to a file with .csv extension.
+ *
+ * @param path String filepath to target file.
+ * @return boolean true or false.
+ */
+ private boolean isValidCsvFile(String path) {
+ return path.endsWith(".csv");
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 4fb71f23103..ea6747a0b90 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,33 +1,245 @@
package seedu.address.logic.parser;
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUP;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
-import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.stream.Stream;
+import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindInterviewCommand;
+import seedu.address.logic.commands.FindPersonCommand;
+import seedu.address.logic.commands.FindTaskCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Stage;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
/**
* Parses input arguments and creates a new FindCommand object
*/
public class FindCommandParser implements Parser {
+ public static final String EXTRA_FLAG_ERROR = "Extra g/ flag found.\n";
+ public static final String NO_KEYWORDS_ERROR = "Some g/ flags are empty.\n";
+ protected static String padding = " ";
+ private static Logger logger = LogsCenter.getLogger(FindCommandParser.class);
+
/**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
+ * Parses the initial input taken from the application
+ *
+ * @param input The input passed from the application.
+ * @return A Find(Person/Interview/Tasks)Command object ready for execution or an error when no type is found
+ * @throws ParseException A search term has an invalid format.
*/
- public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ public FindCommand parse(String input) throws ParseException {
+ logger.info("Parsing Input for Find -> \"" + input + "\"");
+
+ String type = ArgumentTokenizer.getType(input.trim());
+ String args = input.trim().substring(3);
+
+ // splits tokens by its groups
+ ArgumentMultimap groupTokens = ArgumentTokenizer.tokenize(args, PREFIX_GROUP);
+ List allGroups = groupTokens.getAllValues(PREFIX_GROUP);
+
+ switch (type) {
+ case TYPE_PERSON:
+ checkValidGroups(allGroups, args, FindPersonCommand.MESSAGE_USAGE);
+ return new FindPersonCommandParser().parse(allGroups);
+ case TYPE_INTERVIEW:
+ checkValidGroups(allGroups, args, FindInterviewCommand.MESSAGE_USAGE);
+ return new FindInterviewCommandParser().parse(allGroups);
+ case TYPE_TASK:
+ checkValidGroups(allGroups, args, FindTaskCommand.MESSAGE_USAGE);
+ return new FindTaskCommandParser().parse(allGroups);
+ default:
+ return null;
+ }
+ }
+
+ // ------ Checks input for any invalid data ------ //
+
+ private void checkValidGroups(List allGroups, String args, String msg) throws ParseException {
+ boolean isCompletelyEmpty = args.isEmpty();
+ boolean hasNoSpaceBetweenInitialFlags = allGroups.isEmpty();
+ boolean hasNoKeywords = allGroups.stream().anyMatch(grp -> grp.strip().equals(""));
+ boolean stillHasGroupFlag = allGroups.stream()
+ .anyMatch(grp -> grp.strip().startsWith(String.valueOf(PREFIX_GROUP)));
+
+ if (hasNoKeywords) {
+ throw new ParseException(NO_KEYWORDS_ERROR + msg);
+ }
+
+ if (stillHasGroupFlag) {
+ throw new ParseException(EXTRA_FLAG_ERROR + msg);
+ }
+
+ if (isCompletelyEmpty || hasNoSpaceBetweenInitialFlags) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, msg));
}
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ // check for cases where there are no flags after the 'g/' flag
+ for (String group : allGroups) {
+ String firstArg = group.strip().split("\\s+")[0];
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ if (!havePrefixesPresent(padding + firstArg, PREFIX_NAME, PREFIX_PHONE,
+ PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE, PREFIX_DATE, PREFIX_TIME,
+ PREFIX_GROUP, PREFIX_INFORMATION, PREFIX_HEADER)) {
+ throw new ParseException(NO_KEYWORDS_ERROR + msg);
+ }
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid dates.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A date was found to have invalid format.
+ */
+ protected static void checkInvalidDates(List dates, String group) throws ParseException {
+ if (dates.stream().anyMatch(d -> !Date.isValidDate(d.strip()))) {
+ throw new ParseException("[" + group + "] contains invalid date\n" + Date.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid time.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A time was found to have invalid format.
+ */
+ protected static void checkInvalidTime(List times, String group) throws ParseException {
+ if (times.stream().anyMatch(t -> !Time.isValidTime(t.strip()))) {
+ throw new ParseException("[" + group + "] contains invalid time\n" + Time.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid names.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A name was found to have invalid format.
+ */
+ protected static void checkInvalidName(List names, String group) throws ParseException {
+ if (names.stream().anyMatch(n -> !Name.isValidName(n.strip()))) {
+ throw new ParseException("[" + group + "] contains invalid name\n" + Name.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid header.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A header was found to have invalid format.
+ */
+ public static void checkInvalidHeader(List header, String group) throws ParseException {
+ if (header.stream().anyMatch(h -> !Header.isValidHeader(h.strip()))) {
+ throw new ParseException("[" + group + "] contains invalid header\n" + Header.MESSAGE_CONSTRAINTS);
+ }
}
+
+ /**
+ * Checks the current group for any invalid jobs.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A job was found to have invalid format.
+ */
+ protected static void checkInvalidJob(List jobs, String group) throws ParseException {
+ if (jobs.stream().anyMatch(j -> !Job.isValidJob(j.strip()))) {
+ throw new ParseException("[" + group + "] contains invalid job\n" + Job.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid phone numbers.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A phone number was found to have invalid format.
+ */
+ protected static void checkInvalidPhone(List phones, String group) throws ParseException {
+ if (phones.stream().anyMatch(p -> !Phone.isValidPhone(p))) {
+ throw new ParseException("[" + group + "] contains invalid phone number\n"
+ + Phone.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid emails.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException An email was found to have invalid format.
+ */
+ protected static void checkInvalidEmail(List emails, String group) throws ParseException {
+ if (emails.stream().anyMatch(e -> !Email.isValidEmail(e))) {
+ throw new ParseException("[" + group + "] contains invalid email\n" + Email.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid addresses.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException An address was found to have invalid format.
+ */
+ protected static void checkInvalidAddress(List addresses, String group) throws ParseException {
+ if (addresses.stream().anyMatch(a -> !Address.isValidAddress(a))) {
+ throw new ParseException("[" + group + "] contains invalid address\n" + Address.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid stages.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException A stage was found to have invalid format.
+ */
+ protected static void checkInvalidStage(List stages, String group) throws ParseException {
+ if (stages.stream().anyMatch(s -> !Stage.isValidStage(s))) {
+ throw new ParseException("[" + group + "] contains invalid stage\n" + Stage.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ /**
+ * Checks the current group for any invalid information.
+ *
+ * @param group Current group of tokens.
+ * @throws ParseException An information was found to have invalid format.
+ */
+ protected static void checkInvalidInformation(List infos, String group) throws ParseException {
+ if (infos.stream().anyMatch(i -> !Information.isValidInformation(i))) {
+ throw new ParseException(
+ "[" + group + "] contains invalid information\n" + Information.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ protected static boolean havePrefixesPresent(String group, Prefix... prefixes) {
+ ArgumentMultimap allFlags = ArgumentTokenizer.tokenize(padding + group, PREFIX_NAME, PREFIX_PHONE,
+ PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE, PREFIX_DATE, PREFIX_TIME,
+ PREFIX_GROUP, PREFIX_INFORMATION, PREFIX_HEADER);
+
+ return Stream.of(prefixes).anyMatch(prefix -> allFlags.getValue(prefix).isPresent());
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/FindInterviewCommandParser.java b/src/main/java/seedu/address/logic/parser/FindInterviewCommandParser.java
new file mode 100644
index 00000000000..deeb0338f5d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindInterviewCommandParser.java
@@ -0,0 +1,50 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUP;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.List;
+
+import seedu.address.logic.commands.FindInterviewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.interview.InterviewContainsKeywordsPredicate;
+
+public class FindInterviewCommandParser extends FindCommandParser {
+
+ /**
+ * Checks for any data that does not follow format.
+ *
+ * @param groups All groups captured by the g/ flag.
+ * @return A new FindInterViewCommand Object ready for execution.
+ * @throws ParseException An invalid input was found.
+ */
+ public FindInterviewCommand parse(List groups) throws ParseException {
+
+ for (String group : groups) {
+
+ if (havePrefixesPresent(group, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_STAGE,
+ PREFIX_GROUP, PREFIX_INFORMATION, PREFIX_HEADER)) {
+ throw new ParseException("[" + group + "] Invalid flags are found.");
+ }
+
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(
+ padding + group, PREFIX_NAME, PREFIX_DATE, PREFIX_TIME, PREFIX_JOB);
+
+ checkInvalidDates(fields.getAllValues(PREFIX_DATE), group);
+ checkInvalidTime(fields.getAllValues(PREFIX_TIME), group);
+ checkInvalidName(fields.getAllValues(PREFIX_NAME), group);
+ checkInvalidJob(fields.getAllValues(PREFIX_JOB), group);
+ }
+
+ return new FindInterviewCommand(new InterviewContainsKeywordsPredicate(groups));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindPersonCommandParser.java b/src/main/java/seedu/address/logic/parser/FindPersonCommandParser.java
new file mode 100644
index 00000000000..d8fc334d7f3
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindPersonCommandParser.java
@@ -0,0 +1,53 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUP;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.List;
+
+import seedu.address.logic.commands.FindPersonCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
+
+public class FindPersonCommandParser extends FindCommandParser {
+
+ /**
+ * Checks for any data that does not follow format.
+ *
+ * @param groups All groups captured by the g/ flag.
+ * @return A new FindPersonCommand Object ready for execution.
+ * @throws ParseException An invalid input was found.
+ */
+ public FindPersonCommand parse(List groups) throws ParseException {
+
+ for (String group : groups) {
+
+ if (havePrefixesPresent(group, PREFIX_DATE, PREFIX_TIME, PREFIX_GROUP,
+ PREFIX_INFORMATION, PREFIX_HEADER)) {
+ throw new ParseException("[" + group + "] Invalid flags are found.");
+ }
+
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(padding + group, PREFIX_NAME, PREFIX_PHONE,
+ PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE);
+
+ checkInvalidName(fields.getAllValues(PREFIX_NAME), group);
+ checkInvalidPhone(fields.getAllValues(PREFIX_PHONE), group);
+ checkInvalidEmail(fields.getAllValues(PREFIX_EMAIL), group);
+ checkInvalidAddress(fields.getAllValues(PREFIX_ADDRESS), group);
+ checkInvalidJob(fields.getAllValues(PREFIX_JOB), group);
+ checkInvalidStage(fields.getAllValues(PREFIX_STAGE), group);
+ }
+
+ return new FindPersonCommand(new PersonContainsKeywordsPredicate(groups));
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java
new file mode 100644
index 00000000000..16fdfea0e19
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java
@@ -0,0 +1,51 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUP;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+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_STAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.List;
+
+import seedu.address.logic.commands.FindTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tasks.TaskContainsKeywordPredicate;
+
+
+public class FindTaskCommandParser extends FindCommandParser {
+
+ /**
+ * Checks for any data that does not follow format.
+ *
+ * @param groups All groups captured by the g/ flag.
+ * @return A new FindTaskCommand Object ready for execution.
+ * @throws ParseException An invalid input was found.
+ */
+ public FindTaskCommand parse(List groups) throws ParseException {
+
+ for (String group : groups) {
+ if (havePrefixesPresent(group, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_JOB,
+ PREFIX_STAGE, PREFIX_GROUP)) {
+ throw new ParseException("[" + group + "] Invalid flags are found.");
+ }
+
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(padding + group, PREFIX_HEADER,
+ PREFIX_INFORMATION, PREFIX_DATE, PREFIX_TIME);
+
+ checkInvalidHeader(fields.getAllValues(PREFIX_HEADER), group);
+ checkInvalidInformation(fields.getAllValues(PREFIX_INFORMATION), group);
+ checkInvalidDates(fields.getAllValues(PREFIX_DATE), group);
+ checkInvalidTime(fields.getAllValues(PREFIX_TIME), group);
+ }
+
+ return new FindTaskCommand(new TaskContainsKeywordPredicate(groups));
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/ImportCommandParser.java b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java
new file mode 100644
index 00000000000..b9dde0aba34
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ImportCommandParser.java
@@ -0,0 +1,120 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.commons.util.FileUtil;
+import seedu.address.logic.commands.ImportCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.Phone;
+import seedu.address.model.person.Stage;
+
+
+public class ImportCommandParser implements Parser {
+
+ public static final String FILE_DOES_NOT_EXIST = "The file does not exists or it is not an actual file.\n"
+ + "If using relative path, your current working directory is "
+ + System.getProperty("user.dir");
+
+ public static final String INVALID_FILE_PATH = "That is not a valid file path\n"
+ + "Please check for any illegal characters.";
+
+ public static final String PARSE_ERROR = "File cannot be parsed due to IO error.";
+ public static final String WRONG_FILE_TYPE = "No csv file extension found";
+ private static final int NUM_OF_FIELDS = 6;
+
+ @Override
+ public ImportCommand parse(String args) throws ParseException {
+ String filepath = args.strip();
+ checkFilePath(filepath);
+
+ try {
+ return new ImportCommand(readCsv(Paths.get(filepath)));
+ } catch (IOException e) {
+ throw new ParseException(PARSE_ERROR);
+ }
+ }
+
+ private List readCsv(Path path) throws IOException, ParseException {
+ requireNonNull(path);
+ List persons = new ArrayList<>();
+ List entries = FileUtil.readFromFileLines(path);
+
+ for (int i = 0; i < entries.size(); i++) {
+ String[] allFields = entries.get(i).strip().split("\t");
+ ArrayList strippedFields = getFields(allFields, i + 1);
+ Person newPerson = createPerson(strippedFields, i + 1);
+ updatePersons(persons, newPerson, i + 1);
+ }
+
+ return persons;
+ }
+
+ private void checkFilePath(String path) throws ParseException {
+ if (path.equals("")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE));
+ } else if (!FileUtil.isValidPath(path)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, INVALID_FILE_PATH));
+ } else if (!FileUtil.isFileExists(Paths.get(path))) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FILE_DOES_NOT_EXIST));
+ } else if (!(path.endsWith(".csv"))) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, WRONG_FILE_TYPE));
+ }
+ }
+
+ private ArrayList getFields(String[] allFields, int lineNo) throws ParseException {
+ ArrayList strippedFields = new ArrayList<>();
+
+ for (String f : allFields) {
+ String field = f.strip();
+
+ if (!field.equals("")) {
+ strippedFields.add(field);
+ }
+ }
+
+ if (strippedFields.size() != NUM_OF_FIELDS) {
+ throw new ParseException("Line " + lineNo + ": length of fields is not correct");
+ }
+
+ return strippedFields;
+ }
+
+ private Person createPerson(ArrayList fields, int lineNo) throws ParseException {
+ assert fields.size() == NUM_OF_FIELDS : "Number of fields are incorrect";
+
+ try {
+ Name name = ParserUtil.parseName(fields.get(0).strip());
+ Phone phone = ParserUtil.parsePhone(fields.get(1).strip());
+ Email email = ParserUtil.parseEmail(fields.get(2).strip());
+ Address address = ParserUtil.parseAddress(fields.get(3).strip());
+ Job job = ParserUtil.parseJob(fields.get(4).strip());
+ Stage stage = ParserUtil.parseStage(fields.get(5).strip());
+ return new Person(name, phone, email, address, job, stage);
+ } catch (ParseException e) {
+ throw new ParseException("Line " + lineNo + ": " + e.getMessage());
+ }
+ }
+
+ private void updatePersons(List persons, Person newPerson, int lineNo) throws ParseException {
+ requireNonNull(newPerson);
+ boolean isUniquePerson = persons.stream().noneMatch(p -> p.isSamePerson(newPerson));
+
+ if (isUniquePerson) {
+ persons.add(newPerson);
+ } else {
+ throw new ParseException("Line " + lineNo + " applicant is duplicated in csv file.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ListCommandParser.java b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
new file mode 100644
index 00000000000..5cf7864fa34
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.TYPE_INTERVIEW;
+import static seedu.address.logic.parser.CliSyntax.TYPE_PERSON;
+import static seedu.address.logic.parser.CliSyntax.TYPE_TASK;
+
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.ListInterviewCommand;
+import seedu.address.logic.commands.ListPersonCommand;
+import seedu.address.logic.commands.ListTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class ListCommandParser implements Parser {
+
+ /**
+ * Parse ListCommand
+ */
+ public ListCommand parse(String args) throws ParseException {
+ String type = ArgumentTokenizer.getType(args.trim());
+ String removedType = args.trim().substring(3);
+
+ if (removedType.length() != 0) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE));
+ }
+
+ switch (type) {
+ case TYPE_PERSON:
+ return new ListPersonCommand();
+ case TYPE_INTERVIEW:
+ return new ListInterviewCommand();
+ case TYPE_TASK:
+ return new ListTaskCommand();
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..898c7c5c8af 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,18 +2,20 @@
import static java.util.Objects.requireNonNull;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.person.Stage;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
+
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -25,6 +27,7 @@ public class ParserUtil {
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
+ *
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
@@ -65,6 +68,36 @@ public static Phone parsePhone(String phone) throws ParseException {
return new Phone(trimmedPhone);
}
+ /**
+ * Parses a {@code String date} into a {@code Date}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code date} is invalid.
+ */
+ public static Date parseDate(String date) throws ParseException {
+ requireNonNull(date);
+ String trimmedDate = date.trim();
+ if (!Date.isValidDate(trimmedDate)) {
+ throw new ParseException(Date.MESSAGE_CONSTRAINTS);
+ }
+ return new Date(trimmedDate);
+ }
+
+ /**
+ * Parses a {@code String time} into a {@code Time}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code time} is invalid.
+ */
+ public static Time parseTime(String time) throws ParseException {
+ requireNonNull(time);
+ String trimmedTime = time.trim();
+ if (!Time.isValidTime(trimmedTime)) {
+ throw new ParseException(Time.MESSAGE_CONSTRAINTS);
+ }
+ return new Time(trimmedTime);
+ }
+
/**
* Parses a {@code String address} into an {@code Address}.
* Leading and trailing whitespaces will be trimmed.
@@ -96,29 +129,63 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String job} into a {@code Job}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @throws ParseException if the given {@code job} is invalid.
*/
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ public static Job parseJob(String job) throws ParseException {
+ requireNonNull(job);
+ String trimmedJob = job.trim();
+ if (!Job.isValidJob(trimmedJob)) {
+ throw new ParseException(Job.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new Job(trimmedJob);
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses a {@code String stage} into a {@code Stage}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code stage} is invalid.
+ */
+ public static Stage parseStage(String stage) throws ParseException {
+ requireNonNull(stage);
+ String trimmedStage = stage.trim();
+ if (!Stage.isValidStage(trimmedStage)) {
+ throw new ParseException(Stage.MESSAGE_CONSTRAINTS);
+ }
+ return new Stage(trimmedStage);
+ }
+
+ /**
+ * Parses a {@code String header} into a {@code Header}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code header} is invalid.
*/
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
+ public static Header parseHeader(String header) throws ParseException {
+ requireNonNull(header);
+ String trimmedHeader = header.trim();
+ if (!Header.isValidHeader(trimmedHeader)) {
+ throw new ParseException(Header.MESSAGE_CONSTRAINTS);
}
- return tagSet;
+ return new Header(trimmedHeader);
+ }
+
+ /**
+ * Parses a {@code String information} into a {@code Information}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code information} is invalid.
+ */
+ public static Information parseInformation(String information) throws ParseException {
+ requireNonNull(information);
+ String trimmedInformation = information.trim();
+ if (!Information.isValidInformation(trimmedInformation)) {
+ throw new ParseException(Information.MESSAGE_CONSTRAINTS);
+ }
+ return new Information(trimmedInformation);
}
}
+
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/address/logic/parser/Prefix.java
index c859d5fa5db..202a44a7c9a 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/seedu/address/logic/parser/Prefix.java
@@ -2,7 +2,7 @@
/**
* A prefix that marks the beginning of an argument in an arguments string.
- * E.g. 't/' in 'add James t/ friend'.
+ * E.g. 'n/' in 'add [p] n/ James ...'.
*/
public class Prefix {
private final String prefix;
diff --git a/src/main/java/seedu/address/logic/parser/Type.java b/src/main/java/seedu/address/logic/parser/Type.java
new file mode 100644
index 00000000000..ed835319c08
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/Type.java
@@ -0,0 +1,7 @@
+package seedu.address.logic.parser;
+
+public enum Type {
+ PERSON,
+ INTERVIEW,
+ TASK
+}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 1a943a0781a..7d5e2b60b1b 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -5,16 +5,23 @@
import java.util.List;
import javafx.collections.ObservableList;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.interview.UniqueInterviewList;
import seedu.address.model.person.Person;
import seedu.address.model.person.UniquePersonList;
+import seedu.address.model.tasks.Task;
+import seedu.address.model.tasks.UniqueTaskList;
+
/**
* Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
+ * Duplicates are not allowed (by .isSamePerson .isSameInterview .isSameTask comparison)
*/
public class AddressBook implements ReadOnlyAddressBook {
private final UniquePersonList persons;
+ private final UniqueInterviewList interviews;
+ private final UniqueTaskList tasks;
/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
@@ -25,12 +32,14 @@ public class AddressBook implements ReadOnlyAddressBook {
*/
{
persons = new UniquePersonList();
+ interviews = new UniqueInterviewList();
+ tasks = new UniqueTaskList();
}
public AddressBook() {}
/**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
+ * Creates an AddressBook using {@code toBeCopied}
*/
public AddressBook(ReadOnlyAddressBook toBeCopied) {
this();
@@ -40,26 +49,44 @@ public AddressBook(ReadOnlyAddressBook toBeCopied) {
//// list overwrite operations
/**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
+ * Replaces the contents of the applicant list with {@code persons}.
+ * {@code persons} must not contain duplicate applicants.
*/
public void setPersons(List persons) {
this.persons.setPersons(persons);
}
+ /**
+ * Replaces the contents of the interview list with {@code interviews}.
+ * {@code interviews} must not contain duplicate interviews.
+ */
+ public void setInterviews(List interviews) {
+ this.interviews.setInterviews(interviews);
+ }
+
+
+ /**
+ * Replaces the contents of the task list with {@code tasks}.
+ * {@code tasks} must not contain duplicate tasks.
+ */
+ public void setTasks(List tasks) {
+ this.tasks.setTasks(tasks);
+ }
+
/**
* Resets the existing data of this {@code AddressBook} with {@code newData}.
*/
public void resetData(ReadOnlyAddressBook newData) {
requireNonNull(newData);
-
setPersons(newData.getPersonList());
+ setInterviews(newData.getInterviewList());
+ setTasks(newData.getTaskList());
}
//// person-level operations
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Returns true if an applicant with the same identity as {@code person} exists in the address book.
*/
public boolean hasPerson(Person person) {
requireNonNull(person);
@@ -67,17 +94,18 @@ public boolean hasPerson(Person person) {
}
/**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
+ * Adds an applicant to the address book.
+ * The applicant must not already exist in the address book.
*/
public void addPerson(Person p) {
persons.add(p);
}
/**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
+ * Replaces the given applicant {@code target} in the list with {@code editedPerson}.
* {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ * The applicant identity of {@code editedPerson} must not be the same as another
+ * existing applicant in the address book.
*/
public void setPerson(Person target, Person editedPerson) {
requireNonNull(editedPerson);
@@ -93,12 +121,112 @@ public void removePerson(Person key) {
persons.remove(key);
}
+ /**
+ * Resets the existing applicant list.
+ */
+ public void resetPersons() {
+ this.persons.clear();
+ }
+
+
+ //// interview-level operations
+
+ /**
+ * Returns true if an interview with the same identity as {@code interview} exists in the address book.
+ */
+ public boolean hasInterview(Interview interview) {
+ requireNonNull(interview);
+ return interviews.contains(interview);
+ }
+
+ /**
+ * Adds an interview to the address book.
+ * The interview must not already exist in the address book.
+ */
+ public void addInterview(Interview i) {
+ interviews.add(i);
+ }
+
+ /**
+ * Replaces the given interview {@code target} in the list with {@code editedInterview}.
+ * {@code target} must exist in the address book.
+ * The interview identity of {@code editedInterview} must not be the same as another
+ * existing interview in the address book.
+ */
+ public void setInterview(Interview target, Interview editedInterview) {
+ requireNonNull(editedInterview);
+
+ interviews.setInterview(target, editedInterview);
+ }
+
+ /**
+ * Removes {@code key} from this {@code AddressBook}.
+ * {@code key} must exist in the address book.
+ */
+ public void removeInterview(Interview key) {
+ interviews.remove(key);
+ }
+
+ /**
+ * Resets the existing interview list.
+ */
+ public void resetInterviews() {
+ this.interviews.clear();
+ }
+
+ //// task-level operations
+
+ /**
+ * Returns true if a task with the same identity as {@code task} exists in the address book.
+ */
+ public boolean hasTask(Task task) {
+ requireNonNull(task);
+ return tasks.contains(task);
+ }
+
+ /**
+ * Adds a task to the address book.
+ * The task must not already exist in the address book.
+ */
+ public void addTask(Task t) {
+ tasks.add(t);
+ }
+
+ /**
+ * Replaces the given task {@code target} in the list with {@code editedTask}.
+ * {@code target} must exist in the address book.
+ * The task identity of {@code editedTask} must not be the same as another
+ * existing task in the address book.
+ */
+ public void setTask(Task target, Task editedTask) {
+ requireNonNull(editedTask);
+
+ tasks.setTask(target, editedTask);
+ }
+
+ /**
+ * Removes {@code key} from this {@code AddressBook}.
+ * {@code key} must exist in the address book.
+ */
+ public void removeTask(Task key) {
+ tasks.remove(key);
+ }
+
+ /**
+ * Resets the existing task list.
+ */
+ public void resetTasks() {
+ this.tasks.clear();
+ }
+
+
+
+
//// util methods
@Override
public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
- // TODO: refine later
+ return persons.asUnmodifiableObservableList().size() + " applicants";
}
@Override
@@ -106,6 +234,16 @@ public ObservableList getPersonList() {
return persons.asUnmodifiableObservableList();
}
+ @Override
+ public ObservableList getInterviewList() {
+ return interviews.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public ObservableList getTaskList() {
+ return tasks.asUnmodifiableObservableList();
+ }
+
@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
@@ -117,4 +255,5 @@ public boolean equals(Object other) {
public int hashCode() {
return persons.hashCode();
}
+
}
diff --git a/src/main/java/seedu/address/model/Date.java b/src/main/java/seedu/address/model/Date.java
new file mode 100644
index 00000000000..6174ddba82d
--- /dev/null
+++ b/src/main/java/seedu/address/model/Date.java
@@ -0,0 +1,61 @@
+package seedu.address.model;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Represents an interview's or task's date in the interview or task list.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)}
+ */
+public class Date {
+
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Date should be in the format YYYY-MM-dd like 2021-06-25."
+ + "\nDate has to be valid. Example: 2021-02-30 is an invalid date as there is no 30th Feb.";
+ public final String value;
+
+ /**
+ * Constructs a {@code Date}.
+ *
+ * @param date A valid date.
+ */
+ public Date(String date) {
+ requireNonNull(date);
+ checkArgument(isValidDate(date), MESSAGE_CONSTRAINTS);
+ value = date;
+ }
+
+ /**
+ * Returns true if a given string is a valid date.
+ */
+ public static boolean isValidDate(String test) {
+ try {
+ LocalDate.parse(test);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Date // instanceof handles nulls
+ && value.equals(((Date) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..171e0cfc6bd 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -5,7 +5,9 @@
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
/**
* The API of the Model component.
@@ -13,6 +15,8 @@
public interface Model {
/** {@code Predicate} that always evaluate to true */
Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_INTERVIEWS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_TASKS = unused -> true;
/**
* Replaces user prefs data with the data in {@code userPrefs}.
@@ -53,35 +57,120 @@ public interface Model {
ReadOnlyAddressBook getAddressBook();
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Returns true if an applicant with the same identity as {@code person} exists in the address book.
*/
boolean hasPerson(Person person);
/**
- * Deletes the given person.
- * The person must exist in the address book.
+ * Deletes the given applicant.
+ * The applicant must exist in the address book.
*/
void deletePerson(Person target);
/**
- * Adds the given person.
+ * Adds the given applicant.
* {@code person} must not already exist in the address book.
*/
void addPerson(Person person);
/**
- * Replaces the given person {@code target} with {@code editedPerson}.
+ * Replaces the given applicant {@code target} with {@code editedPerson}.
* {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ * The applicant identity of {@code editedPerson} must not be the same as
+ * another existing applicant in the address book.
*/
void setPerson(Person target, Person editedPerson);
- /** Returns an unmodifiable view of the filtered person list */
+ /**
+ * Replaces applicant list data.
+ */
+ void resetPersons();
+
+ /** Returns an unmodifiable view of the filtered applicant list */
ObservableList getFilteredPersonList();
/**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
+ * Updates the filter of the filtered applicant list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate predicate);
+
+ /**
+ * Returns true if an interview with the same identity as {@code interview} exists in the address book.
+ */
+ boolean hasInterview(Interview interview);
+
+ /**
+ * Deletes the given interview.
+ * The interview must exist in the address book.
+ */
+ void deleteInterview(Interview target);
+
+ /**
+ * Adds the given interview.
+ * {@code interview} must not already exist in the address book.
+ */
+ void addInterview(Interview interview);
+
+ /**
+ * Replaces the given interview {@code target} with {@code editedInterview}.
+ * {@code target} must exist in the address book.
+ * The interview identity of {@code editedInterview} must not be the same as another
+ * existing interview in the address book.
+ */
+ void setInterview(Interview target, Interview editedInterview);
+
+ /**
+ * Replaces interview list data.
+ */
+ void resetInterviews();
+
+ /** Returns an unmodifiable view of the filtered interview list */
+ ObservableList getFilteredInterviewList();
+
+ /**
+ * Updates the filter of the filtered interview list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredInterviewList(Predicate predicate);
+
+ /**
+ * Returns true if a task with the same identity as {@code task} exists in the address book.
+ */
+ boolean hasTask(Task task);
+
+ /**
+ * Deletes the given task.
+ * The task must exist in the address book.
+ */
+ void deleteTask(Task target);
+
+ /**
+ * Adds the given task.
+ * {@code task} must not already exist in the address book.
+ */
+ void addTask(Task task);
+
+ /**
+ * Replaces the given task {@code target} with {@code editedTask}.
+ * {@code target} must exist in the address book.
+ * The task identity of {@code editedTask} must not be the same as another existing task in the address book.
+ */
+ void setTask(Task target, Task editedTask);
+
+ /**
+ * Replaces task list data.
+ */
+ void resetTasks();
+
+ /** Returns an unmodifiable view of the filtered task list */
+ ObservableList getFilteredTaskList();
+
+ /**
+ * Updates the filter of the filtered task list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredTaskList(Predicate predicate);
+
+
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 86c1df298d7..662c57bf355 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -11,7 +11,9 @@
import javafx.collections.transformation.FilteredList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
/**
* Represents the in-memory model of the address book data.
@@ -22,6 +24,8 @@ public class ModelManager implements Model {
private final AddressBook addressBook;
private final UserPrefs userPrefs;
private final FilteredList filteredPersons;
+ private final FilteredList filteredInterviews;
+ private final FilteredList filteredTasks;
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
@@ -34,6 +38,8 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ filteredInterviews = new FilteredList<>(this.addressBook.getInterviewList());
+ filteredTasks = new FilteredList<>(this.addressBook.getTaskList());
}
public ModelManager() {
@@ -82,6 +88,7 @@ public void setAddressBook(ReadOnlyAddressBook addressBook) {
this.addressBook.resetData(addressBook);
}
+
@Override
public ReadOnlyAddressBook getAddressBook() {
return addressBook;
@@ -111,7 +118,71 @@ public void setPerson(Person target, Person editedPerson) {
addressBook.setPerson(target, editedPerson);
}
- //=========== Filtered Person List Accessors =============================================================
+ @Override
+ public void resetPersons() {
+ this.addressBook.resetPersons();
+ }
+
+
+ @Override
+ public boolean hasInterview(Interview interview) {
+ requireNonNull(interview);
+ return addressBook.hasInterview(interview);
+ }
+
+ @Override
+ public void deleteInterview(Interview target) {
+ addressBook.removeInterview(target);
+ }
+
+ @Override
+ public void addInterview(Interview interview) {
+ addressBook.addInterview(interview);
+ updateFilteredInterviewList(PREDICATE_SHOW_ALL_INTERVIEWS);
+ }
+
+ @Override
+ public void setInterview(Interview target, Interview editedInterview) {
+ requireAllNonNull(target, editedInterview);
+ addressBook.setInterview(target, editedInterview);
+ }
+
+ @Override
+ public void resetInterviews() {
+ this.addressBook.resetInterviews();
+ }
+
+ @Override
+ public boolean hasTask(Task person) {
+ requireNonNull(person);
+ return addressBook.hasTask(person);
+ }
+
+ @Override
+ public void deleteTask(Task target) {
+ addressBook.removeTask(target);
+ }
+
+ @Override
+ public void addTask(Task task) {
+ addressBook.addTask(task);
+ updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ }
+
+ @Override
+ public void setTask(Task target, Task editedTask) {
+ requireAllNonNull(target, editedTask);
+
+ addressBook.setTask(target, editedTask);
+ }
+
+ @Override
+ public void resetTasks() {
+ this.addressBook.resetTasks();
+ }
+
+
+ //=========== Filtered List Accessors =============================================================
/**
* Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
@@ -128,6 +199,37 @@ public void updateFilteredPersonList(Predicate predicate) {
filteredPersons.setPredicate(predicate);
}
+ /**
+ * Returns an unmodifiable view of the list of {@code Interview} backed by the internal list of
+ * {@code versionedAddressBook}
+ */
+ @Override
+ public ObservableList getFilteredInterviewList() {
+ return filteredInterviews;
+ }
+
+ @Override
+ public void updateFilteredInterviewList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredInterviews.setPredicate(predicate);
+ }
+
+ /**
+ * Returns an unmodifiable view of the list of {@code Task} backed by the internal list of
+ * {@code versionedAddressBook}
+ */
+ @Override
+ public ObservableList getFilteredTaskList() {
+ return filteredTasks;
+ }
+
+ @Override
+ public void updateFilteredTaskList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredTasks.setPredicate(predicate);
+ }
+
+
@Override
public boolean equals(Object obj) {
// short circuit if same object
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
index 6ddc2cd9a29..2bb58ba1e67 100644
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
@@ -1,17 +1,18 @@
package seedu.address.model;
import javafx.collections.ObservableList;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
/**
* Unmodifiable view of an address book
*/
public interface ReadOnlyAddressBook {
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
ObservableList getPersonList();
+ ObservableList getInterviewList();
+
+ ObservableList getTaskList();
}
diff --git a/src/main/java/seedu/address/model/Time.java b/src/main/java/seedu/address/model/Time.java
new file mode 100644
index 00000000000..0c35354e223
--- /dev/null
+++ b/src/main/java/seedu/address/model/Time.java
@@ -0,0 +1,65 @@
+package seedu.address.model;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Represents an interview's or task's time in the interview or task list.
+ * Guarantees: immutable; is valid as declared in {@link #isValidTime(String)}
+ */
+public class Time {
+
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Time should be in the format HH:MM like 09:41"
+ + "\n Time has to be valid (00:00-23:59). Example: 24:01 is an invalid time.";
+ public final String value;
+
+ /**
+ * Constructs a {@code Time}.
+ *
+ * @param time A valid time.
+ */
+ public Time(String time) {
+ requireNonNull(time);
+ checkArgument(isValidTime(time), MESSAGE_CONSTRAINTS);
+ value = time;
+ }
+
+ /**
+ * Returns true if a given string is a valid time.
+ */
+ public static boolean isValidTime(String test) {
+ try {
+ LocalTime.parse(test, DateTimeFormatter.ofPattern("HH:mm"));
+ if (test.equals("24:00")) {
+ return false;
+ }
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Time // instanceof handles nulls
+ && value.equals(((Time) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/interview/Interview.java b/src/main/java/seedu/address/model/interview/Interview.java
new file mode 100644
index 00000000000..59f908b733d
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/Interview.java
@@ -0,0 +1,94 @@
+package seedu.address.model.interview;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Objects;
+
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a Interview in the interview list.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Interview {
+
+ // Identity fields
+ private final Person person;
+
+ // Data fields
+ private final Date date;
+ private final Time time;
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Interview(Person person, Date date, Time time) {
+ requireAllNonNull(person, date, time);
+ this.person = person;
+ this.date = date;
+ this.time = time;
+ }
+
+ public Person getPerson() {
+ return person;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public Time getTime() {
+ return time;
+ }
+
+ /**
+ * Returns true if both interviews have the same person or same date and time.
+ * This defines a weaker notion of equality between two interviews.
+ */
+ public boolean isSameInterview(Interview otherInterview) {
+ return otherInterview != null
+ && (otherInterview.getDate().equals(getDate())
+ && otherInterview.getTime().equals(getTime()));
+ }
+
+ /**
+ * Returns true if both interviews have the same identity and data fields.
+ * This defines a stronger notion of equality between two interviews.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Interview)) {
+ return false;
+ }
+
+ Interview otherInterview = (Interview) other;
+ return otherInterview.getPerson().isSamePerson(getPerson())
+ && otherInterview.getDate().equals(getDate())
+ && otherInterview.getTime().equals(getTime());
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(person, date, time);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getPerson())
+ .append("; Date: ")
+ .append(getDate())
+ .append("; Time: ")
+ .append(getTime());
+ return builder.toString();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/interview/InterviewContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/interview/InterviewContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..0689e9bcd9e
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/InterviewContainsKeywordsPredicate.java
@@ -0,0 +1,74 @@
+package seedu.address.model.interview;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+
+public class InterviewContainsKeywordsPredicate implements Predicate {
+ private List keywords;
+
+ public InterviewContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Interview interview) {
+
+ for (String group : keywords) {
+ boolean containsAllGroupTerms = true;
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(
+ " " + group, PREFIX_DATE, PREFIX_TIME, PREFIX_NAME, PREFIX_JOB);
+
+ List dates = fields.getAllValues(PREFIX_DATE);
+ List times = fields.getAllValues(PREFIX_TIME);
+ List names = fields.getAllValues(PREFIX_NAME);
+ List jobs = fields.getAllValues(PREFIX_JOB);
+
+ if (!dates.isEmpty() && !dates.stream().allMatch(d -> interview.getDate().toString().contains(d))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!times.isEmpty() && !times.stream().allMatch(t-> interview.getTime().toString().contains(t))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!names.isEmpty() && !names.stream().allMatch(n -> interview.getPerson().getName().contains(n))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!jobs.isEmpty() && !jobs.stream().allMatch(j -> interview.getPerson().getJob().contains(j))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (containsAllGroupTerms) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InterviewContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ // state check
+ InterviewContainsKeywordsPredicate e = (InterviewContainsKeywordsPredicate) other;
+ return keywords.equals(e.keywords);
+ }
+}
diff --git a/src/main/java/seedu/address/model/interview/InterviewDateTimeComparator.java b/src/main/java/seedu/address/model/interview/InterviewDateTimeComparator.java
new file mode 100644
index 00000000000..e652136d168
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/InterviewDateTimeComparator.java
@@ -0,0 +1,27 @@
+package seedu.address.model.interview;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.Comparator;
+
+public class InterviewDateTimeComparator implements Comparator {
+ @Override
+ public int compare(Interview o1, Interview o2) {
+ LocalDate o1Date = LocalDate.parse(o1.getDate().value);
+ LocalDate o2Date = LocalDate.parse(o2.getDate().value);
+ if (o1Date.isBefore(o2Date)) {
+ return -1;
+ } else if (o1Date.isAfter(o2Date)) {
+ return 1;
+ } else {
+ LocalTime o1Time = LocalTime.parse(o1.getTime().value);
+ LocalTime o2Time = LocalTime.parse(o2.getTime().value);
+ if (o1Time.isBefore(o2Time)) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/address/model/interview/UniqueInterviewList.java b/src/main/java/seedu/address/model/interview/UniqueInterviewList.java
new file mode 100644
index 00000000000..6a71db33093
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/UniqueInterviewList.java
@@ -0,0 +1,145 @@
+package seedu.address.model.interview;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.interview.exceptions.DuplicateInterviewException;
+import seedu.address.model.interview.exceptions.InterviewNotFoundException;
+
+/**
+ * A list of interviews that enforces uniqueness between its elements and does not allow nulls.
+ * A interview is considered unique by comparing using {@code Interview#isSameInterview(Interview)}.
+ * As such, adding and updating of Interviews uses Interview#isSameInterview(Interview)
+ * for equality so as to ensure that the interview being added or updated is unique in terms of
+ * identity in the UniqueInterviewList. However, the removal of a interview uses Interview#equals(Object)
+ * so as to ensure that the interview with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Interview#isSameInterview(Interview)
+ */
+public class UniqueInterviewList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent interview as the given argument.
+ */
+ public boolean contains(Interview toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameInterview);
+ }
+
+ /**
+ * Adds an interview to the list.
+ * The interview must not already exist in the list.
+ */
+ public void add(Interview toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateInterviewException();
+ }
+ internalList.add(toAdd);
+ sortInterviews();
+ }
+
+ /**
+ * Replaces the interview {@code target} in the list with {@code editedInterview}.
+ * {@code target} must exist in the list.
+ * The interview identity of {@code editedInterview} must not be the same as another existing interview in the list.
+ */
+ public void setInterview(Interview target, Interview editedInterview) {
+ requireAllNonNull(target, editedInterview);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new InterviewNotFoundException();
+ }
+
+ if (!target.isSameInterview(editedInterview) && contains(editedInterview)) {
+ throw new DuplicateInterviewException();
+ }
+ internalList.set(index, editedInterview);
+ sortInterviews();
+ }
+
+ /**
+ * Removes the equivalent interview from the list.
+ * The interview must exist in the list.
+ */
+ public void remove(Interview toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new InterviewNotFoundException();
+ }
+ sortInterviews();
+ }
+
+ public void sortInterviews() {
+ internalList.sort(new InterviewDateTimeComparator());
+ }
+
+ public void clear() {
+ internalList.clear();
+ }
+
+ /**
+ * Replaces the contents of this list with {@code interviews}.
+ * {@code interviews} must not contain duplicate interviews.
+ */
+ public void setInterviews(List interviews) {
+ requireAllNonNull(interviews);
+ if (!interviewsAreUnique(interviews)) {
+ throw new DuplicateInterviewException();
+ }
+ internalList.setAll(interviews);
+ sortInterviews();
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof seedu.address.model.interview.UniqueInterviewList // instanceof handles nulls
+ && internalList.equals(((seedu.address.model.interview.UniqueInterviewList) other)
+ .internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code interviews} contains only unique interviews.
+ */
+ private boolean interviewsAreUnique(List interviews) {
+ for (int i = 0; i < interviews.size() - 1; i++) {
+ for (int j = i + 1; j < interviews.size(); j++) {
+ if (interviews.get(i).isSameInterview(interviews.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/interview/exceptions/DuplicateInterviewException.java b/src/main/java/seedu/address/model/interview/exceptions/DuplicateInterviewException.java
new file mode 100644
index 00000000000..dc99ff8b411
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/exceptions/DuplicateInterviewException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.interview.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Interviews
+ * (Interviews are considered duplicates if they have the same identity).
+ */
+public class DuplicateInterviewException extends RuntimeException {
+ public DuplicateInterviewException() {
+ super("Operation would result in duplicate interviews");
+ }
+}
diff --git a/src/main/java/seedu/address/model/interview/exceptions/InterviewNotFoundException.java b/src/main/java/seedu/address/model/interview/exceptions/InterviewNotFoundException.java
new file mode 100644
index 00000000000..7ae3850c232
--- /dev/null
+++ b/src/main/java/seedu/address/model/interview/exceptions/InterviewNotFoundException.java
@@ -0,0 +1,7 @@
+package seedu.address.model.interview.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified interview.
+ */
+public class InterviewNotFoundException extends RuntimeException {}
+
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
index 60472ca22a0..507a010a98c 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/person/Address.java
@@ -4,7 +4,7 @@
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's address in the address book.
+ * Represents an applicant's address in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
*/
public class Address {
@@ -31,12 +31,17 @@ public Address(String address) {
}
/**
- * Returns true if a given string is a valid email.
+ * Returns true if a given string is a valid address.
*/
public static boolean isValidAddress(String test) {
return test.matches(VALIDATION_REGEX);
}
+
+ public boolean contains(String s) {
+ return value.toLowerCase().contains(s.toLowerCase().strip());
+ }
+
@Override
public String toString() {
return value;
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java
index f866e7133de..e582f24b3de 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/address/model/person/Email.java
@@ -4,7 +4,7 @@
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's email in the address book.
+ * Represents an applicant's email in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
*/
public class Email {
@@ -51,6 +51,10 @@ public static boolean isValidEmail(String test) {
return test.matches(VALIDATION_REGEX);
}
+ public boolean contains(String s) {
+ return value.toLowerCase().contains(s.toLowerCase().strip());
+ }
+
@Override
public String toString() {
return value;
diff --git a/src/main/java/seedu/address/model/person/Job.java b/src/main/java/seedu/address/model/person/Job.java
new file mode 100644
index 00000000000..4c4bd7c4885
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Job.java
@@ -0,0 +1,68 @@
+package seedu.address.model.person;
+
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents the job applied by an applicant in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidJob(String)}
+ */
+public class Job {
+
+ public static final String MESSAGE_CONSTRAINTS = "Job should only contain alphanumeric "
+ + "characters and spaces, and it should not be blank";
+
+ /*
+ * The first character of the job 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 jobTitle;
+
+ /**
+ * Constructs a {@code Job}.
+ *
+ * @param jobTitle A valid job.
+ */
+ public Job(String jobTitle) {
+ requireNonNull(jobTitle);
+ checkArgument(isValidJob(jobTitle), MESSAGE_CONSTRAINTS);
+ this.jobTitle = jobTitle;
+ }
+
+ /**
+ * Returns true if a given string is a valid job.
+ */
+ public static boolean isValidJob(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ public String getJob() {
+ return this.jobTitle;
+ }
+
+ public boolean contains(String s) {
+ return jobTitle.toLowerCase().contains(s.toLowerCase().strip());
+ }
+
+ @Override
+ public String toString() {
+ return jobTitle;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Job // instanceof handles nulls
+ && jobTitle.equals(((Job) other).jobTitle)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return jobTitle.hashCode();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
index 79244d71cf7..5df75d83db1 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/person/Name.java
@@ -4,16 +4,16 @@
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's name in the address book.
+ * Represents an applicant's name in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
*/
public class Name {
- public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ 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,
+ * The first character of the name must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
@@ -39,6 +39,10 @@ public static boolean isValidName(String test) {
}
+ public boolean contains(String s) {
+ return fullName.toLowerCase().contains(s.toLowerCase());
+ }
+
@Override
public String toString() {
return fullName;
@@ -46,9 +50,19 @@ public String toString() {
@Override
public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Name // instanceof handles nulls
- && fullName.equals(((Name) other).fullName)); // state check
+ if (other == this) {
+ return true;
+ } else if (other instanceof Name) {
+ String currentName = fullName.toLowerCase();
+ String otherName = ((Name) other).fullName.toLowerCase();
+ if (currentName.contains(" ") && otherName.contains(" ")) {
+ return currentName.replaceAll("\\s", "")
+ .equals(otherName.replaceAll("\\s", ""));
+ } else {
+ return currentName.equals(otherName);
+ }
+ }
+ return false;
}
@Override
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
deleted file mode 100644
index c9b5868427c..00000000000
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package seedu.address.model.person;
-
-import java.util.List;
-import java.util.function.Predicate;
-
-import seedu.address.commons.util.StringUtil;
-
-/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
- */
-public class NameContainsKeywordsPredicate implements Predicate {
- private final List keywords;
-
- public NameContainsKeywordsPredicate(List keywords) {
- this.keywords = keywords;
- }
-
- @Override
- public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls
- && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index 8ff1d83fe89..9479aad7d3f 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -2,15 +2,10 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
/**
- * Represents a Person in the address book.
+ * Represents an applicant in the address book.
* Guarantees: details are present and not null, field values are validated, immutable.
*/
public class Person {
@@ -22,18 +17,20 @@ public class Person {
// Data fields
private final Address address;
- private final Set tags = new HashSet<>();
+ private final Job job;
+ private final Stage stage;
/**
* 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(Name name, Phone phone, Email email, Address address, Job job, Stage stage) {
+ requireAllNonNull(name, phone, email, address, job, stage);
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
- this.tags.addAll(tags);
+ this.job = job;
+ this.stage = stage;
}
public Name getName() {
@@ -52,17 +49,16 @@ public Address getAddress() {
return address;
}
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
+ public Job getJob() {
+ return job;
}
+ public Stage getStage() {
+ return stage;
+ }
/**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
+ * Returns true if both applicants have the same name.
+ * This defines a weaker notion of equality between two applicants.
*/
public boolean isSamePerson(Person otherPerson) {
if (otherPerson == this) {
@@ -70,12 +66,12 @@ public boolean isSamePerson(Person otherPerson) {
}
return otherPerson != null
- && otherPerson.getName().equals(getName());
+ && (otherPerson.getName().equals(getName()));
}
/**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
+ * Returns true if both applicants have the same identity and data fields.
+ * This defines a stronger notion of equality between two applicants.
*/
@Override
public boolean equals(Object other) {
@@ -92,13 +88,14 @@ public boolean equals(Object other) {
&& otherPerson.getPhone().equals(getPhone())
&& otherPerson.getEmail().equals(getEmail())
&& otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
+ && otherPerson.getJob().equals(getJob())
+ && otherPerson.getStage().equals(getStage());
}
@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(name, phone, email, address, job, stage);
}
@Override
@@ -110,13 +107,12 @@ public String toString() {
.append("; Email: ")
.append(getEmail())
.append("; Address: ")
- .append(getAddress());
+ .append(getAddress())
+ .append("; Job: ")
+ .append(getJob())
+ .append("; Stage: ")
+ .append(getStage());
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
return builder.toString();
}
diff --git a/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..25974ab514c
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java
@@ -0,0 +1,85 @@
+package seedu.address.model.person;
+
+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_JOB;
+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_STAGE;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+
+public class PersonContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public PersonContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ for (String group : keywords) {
+ boolean containsAllGroupTerms = true;
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(" " + group, PREFIX_NAME,
+ PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_JOB, PREFIX_STAGE);
+
+ List names = fields.getAllValues(PREFIX_NAME);
+ List phone = fields.getAllValues(PREFIX_PHONE);
+ List emails = fields.getAllValues(PREFIX_EMAIL);
+ List addresses = fields.getAllValues(PREFIX_ADDRESS);
+ List jobs = fields.getAllValues(PREFIX_JOB);
+ List stages = fields.getAllValues(PREFIX_STAGE);
+
+ if (!names.isEmpty() && !names.stream().allMatch(n -> person.getName().contains(n))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!phone.isEmpty() && !phone.stream().allMatch(p -> person.getPhone().contains(p))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!emails.isEmpty() && !emails.stream().allMatch(e -> person.getEmail().contains(e))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!addresses.isEmpty() && !addresses.stream().allMatch(a -> person.getAddress().contains(a))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!jobs.isEmpty() && !jobs.stream().allMatch(j -> person.getJob().contains(j))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!stages.isEmpty() && !stages.stream().allMatch(s -> person.getStage().contains(s))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (containsAllGroupTerms) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PersonContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ // state check
+ PersonContainsKeywordsPredicate e = (PersonContainsKeywordsPredicate) other;
+ return keywords.equals(e.keywords);
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
index 872c76b382f..e777b5d5215 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/person/Phone.java
@@ -4,7 +4,7 @@
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's phone number in the address book.
+ * Represents a applicant's phone number in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
*/
public class Phone {
@@ -33,6 +33,10 @@ public static boolean isValidPhone(String test) {
return test.matches(VALIDATION_REGEX);
}
+ public boolean contains(String s) {
+ return value.toLowerCase().contains(s.toLowerCase());
+ }
+
@Override
public String toString() {
return value;
diff --git a/src/main/java/seedu/address/model/person/Stage.java b/src/main/java/seedu/address/model/person/Stage.java
new file mode 100644
index 00000000000..176b205b90c
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Stage.java
@@ -0,0 +1,58 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a applicant's job application stage in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidStage(String)}
+ */
+public class Stage {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Stage should be only INPROGRESS or ACCEPTED or REJECTED (case-sensitive)";
+
+ public static final String VALIDATION_REGEX = "INPROGRESS|ACCEPTED|REJECTED";
+
+ public final String value;
+
+ /**
+ * Constructs a {@code Stage}.
+ *
+ * @param stage A valid stage.
+ */
+ public Stage(String stage) {
+ requireNonNull(stage);
+ checkArgument(isValidStage(stage), MESSAGE_CONSTRAINTS);
+ value = stage;
+ }
+
+ /**
+ * Returns true if a given string is a valid stage.
+ */
+ public static boolean isValidStage(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ public boolean contains(String s) {
+ return value.toLowerCase().contains(s.toLowerCase());
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Stage // instanceof handles nulls
+ && value.equals(((Stage) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
index 0fee4fe57e6..99ae7370ade 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/seedu/address/model/person/UniquePersonList.java
@@ -12,11 +12,12 @@
import seedu.address.model.person.exceptions.PersonNotFoundException;
/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
+ * A list of applicants that enforces uniqueness between its elements and does not allow nulls.
+ * An applicant is considered unique by comparing using {@code Person#isSamePerson(Person)}.
+ * As such, adding and updating of applicants uses Person#isSamePerson(Person) for equality
+ * so as to ensure that the applicant being added or updated is unique in terms of identity
+ * in the UniquePersonList. However, the removal of an applicant uses Person#equals(Object) so
+ * as to ensure that the applicant with exactly the same fields will be removed.
*
* Supports a minimal set of list operations.
*
@@ -29,7 +30,7 @@ public class UniquePersonList implements Iterable {
FXCollections.unmodifiableObservableList(internalList);
/**
- * Returns true if the list contains an equivalent person as the given argument.
+ * Returns true if the list contains an equivalent applicant as the given argument.
*/
public boolean contains(Person toCheck) {
requireNonNull(toCheck);
@@ -37,8 +38,8 @@ public boolean contains(Person toCheck) {
}
/**
- * Adds a person to the list.
- * The person must not already exist in the list.
+ * Adds a applicant to the list.
+ * The applicant must not already exist in the list.
*/
public void add(Person toAdd) {
requireNonNull(toAdd);
@@ -49,9 +50,9 @@ public void add(Person toAdd) {
}
/**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
+ * Replaces the applicant {@code target} in the list with {@code editedPerson}.
* {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
+ * The applicant identity of {@code editedPerson} must not be the same as another existing applicant in the list.
*/
public void setPerson(Person target, Person editedPerson) {
requireAllNonNull(target, editedPerson);
@@ -69,8 +70,8 @@ public void setPerson(Person target, Person editedPerson) {
}
/**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
+ * Removes the equivalent applicant from the list.
+ * The applicant must exist in the list.
*/
public void remove(Person toRemove) {
requireNonNull(toRemove);
@@ -79,6 +80,10 @@ public void remove(Person toRemove) {
}
}
+ public void clear() {
+ internalList.clear();
+ }
+
public void setPersons(UniquePersonList replacement) {
requireNonNull(replacement);
internalList.setAll(replacement.internalList);
@@ -86,7 +91,7 @@ public void setPersons(UniquePersonList replacement) {
/**
* Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
+ * {@code persons} must not contain duplicate applicants.
*/
public void setPersons(List persons) {
requireAllNonNull(persons);
@@ -122,7 +127,7 @@ public int hashCode() {
}
/**
- * Returns true if {@code persons} contains only unique persons.
+ * Returns true if {@code persons} contains only unique applicants.
*/
private boolean personsAreUnique(List persons) {
for (int i = 0; i < persons.size() - 1; i++) {
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
index d7290f59442..62d370b71ba 100644
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
@@ -1,11 +1,11 @@
package seedu.address.model.person.exceptions;
/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
+ * Signals that the operation will result in duplicate applicants (Applicants are considered
+ * duplicates if they have the same identity).
*/
public class DuplicatePersonException extends RuntimeException {
public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
+ super("Operation would result in duplicate applicants");
}
}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
index fa764426ca7..33fa07eae8b 100644
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
@@ -1,6 +1,6 @@
package seedu.address.model.person.exceptions;
/**
- * Signals that the operation is unable to find the specified person.
+ * Signals that the operation is unable to find the specified applicant.
*/
public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
deleted file mode 100644
index b0ea7e7dad7..00000000000
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package seedu.address.model.tag;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
- */
-public class Tag {
-
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
-
- public final String tagName;
-
- /**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
- */
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
- }
-
- /**
- * Returns true if a given string is a valid tag name.
- */
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Tag // instanceof handles nulls
- && tagName.equals(((Tag) other).tagName)); // state check
- }
-
- @Override
- public int hashCode() {
- return tagName.hashCode();
- }
-
- /**
- * Format state as text for viewing.
- */
- public String toString() {
- return '[' + tagName + ']';
- }
-
-}
diff --git a/src/main/java/seedu/address/model/tasks/Header.java b/src/main/java/seedu/address/model/tasks/Header.java
new file mode 100644
index 00000000000..7af5dd8a5da
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/Header.java
@@ -0,0 +1,72 @@
+package seedu.address.model.tasks;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a task's header in the taskList.
+ * Guarantees: immutable; is valid as declared in {@link #isValidHeader(String)}
+ */
+public class Header {
+
+ public static final String MESSAGE_CONSTRAINTS = "Header 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 fullHeader;
+
+ /**
+ * Constructs a {@code Header}.
+ * @param header A valid header.
+ */
+ public Header(String header) {
+ requireNonNull(header);
+ checkArgument(isValidHeader(header), MESSAGE_CONSTRAINTS);
+ fullHeader = header;
+ }
+
+ /**
+ * Returns true if a given string is a valid header.
+ */
+ public static boolean isValidHeader(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ public boolean contains(String s) {
+ return fullHeader.toLowerCase().contains(s.toLowerCase());
+ }
+
+ @Override
+ public String toString() {
+ return fullHeader;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ } else if (other instanceof Header) {
+ String currentHeader = fullHeader.toLowerCase();
+ String otherHeader = ((Header) other).fullHeader.toLowerCase();
+ if (currentHeader.contains(" ") && otherHeader.contains(" ")) {
+ return currentHeader.replaceAll("\\s", "")
+ .equals(otherHeader.replaceAll("\\s", ""));
+ } else {
+ return currentHeader.equals(otherHeader);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return fullHeader.hashCode();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/tasks/Information.java b/src/main/java/seedu/address/model/tasks/Information.java
new file mode 100644
index 00000000000..7b662390947
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/Information.java
@@ -0,0 +1,61 @@
+package seedu.address.model.tasks;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a task's information in the taskList.
+ * Guarantees: immutable; is valid as declared in {@link #isValidInformation(String)}
+ */
+public class Information {
+
+ public static final String MESSAGE_CONSTRAINTS = "Information 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 fullInformation;
+
+ /**
+ * Constructs a {@code Information}.
+ * @param information A valid information.
+ */
+ public Information(String information) {
+ requireNonNull(information);
+ checkArgument(isValidInformation(information), MESSAGE_CONSTRAINTS);
+ fullInformation = information;
+ }
+
+ /**
+ * Returns true if a given string is a valid information.
+ */
+ public static boolean isValidInformation(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ public boolean contains(String s) {
+ return fullInformation.toLowerCase().contains(s.toLowerCase());
+ }
+
+ @Override
+ public String toString() {
+ return fullInformation;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Information // instanceof handles nulls
+ && fullInformation.equals(((Information) other).fullInformation)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return fullInformation.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tasks/Task.java b/src/main/java/seedu/address/model/tasks/Task.java
new file mode 100644
index 00000000000..0430e7d1f05
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/Task.java
@@ -0,0 +1,90 @@
+package seedu.address.model.tasks;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+
+public class Task {
+
+ private final Header header;
+ private final Date date;
+ private final Time time;
+ private final Information information;
+ /**
+ * Every field must be present and not null.
+ */
+ public Task(Header header, Date date, Time time, Information information) {
+ requireAllNonNull(header, date, time, information);
+ this.header = header;
+ this.date = date;
+ this.time = time;
+ this.information = information;
+ }
+
+ public Header getHeader() {
+ return header;
+ }
+
+ public Information getInformation() {
+ return information;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public Time getTime() {
+ return time;
+ }
+
+ /**
+ * Returns true if both tasks have the same header, date and time.
+ * This defines a weaker notion of equality between two tasks.
+ */
+ public boolean isSameTask(Task otherTask) {
+ if (otherTask == this) {
+ return true;
+ }
+
+ return otherTask != null
+ && (otherTask.getHeader().equals(getHeader()))
+ && (otherTask.getDate().equals(getDate())
+ && otherTask.getTime().equals(getTime()));
+ }
+
+ /**
+ * Returns true if both tasks have the same identity and data fields.
+ * This defines a stronger notion of equality between two tasks.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Task)) {
+ return false;
+ }
+
+ Task otherTask = (Task) other;
+ return (otherTask.getHeader().equals(getHeader()))
+ && (otherTask.getDate().equals(getDate())
+ && otherTask.getTime().equals(getTime()))
+ && otherTask.getInformation().equals(getInformation());
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getHeader())
+ .append("; Date: ")
+ .append(getDate())
+ .append("; Time: ")
+ .append(getTime())
+ .append("; Information: ")
+ .append(getInformation());
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/tasks/TaskContainsKeywordPredicate.java b/src/main/java/seedu/address/model/tasks/TaskContainsKeywordPredicate.java
new file mode 100644
index 00000000000..87aecb4698e
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/TaskContainsKeywordPredicate.java
@@ -0,0 +1,73 @@
+package seedu.address.model.tasks;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_HEADER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INFORMATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TIME;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+
+public class TaskContainsKeywordPredicate implements Predicate {
+ private final List keywords;
+
+ public TaskContainsKeywordPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Task task) {
+ for (String group : keywords) {
+ boolean containsAllGroupTerms = true;
+ ArgumentMultimap fields = ArgumentTokenizer.tokenize(" " + group,
+ PREFIX_HEADER, PREFIX_INFORMATION, PREFIX_DATE, PREFIX_TIME);
+
+ List headers = fields.getAllValues(PREFIX_HEADER);
+ List infos = fields.getAllValues(PREFIX_INFORMATION);
+ List dates = fields.getAllValues(PREFIX_DATE);
+ List times = fields.getAllValues(PREFIX_TIME);
+
+ if (!headers.isEmpty() && !headers.stream().allMatch(h -> task.getHeader().contains(h))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!infos.isEmpty() && !infos.stream().allMatch(t -> task.getInformation().contains(t))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!dates.isEmpty() && !dates.stream().allMatch(d -> task.getDate().toString().contains(d))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (!times.isEmpty() && !times.stream().allMatch(t-> task.getTime().toString().contains(t))) {
+ containsAllGroupTerms = false;
+ }
+
+ if (containsAllGroupTerms) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof TaskContainsKeywordPredicate)) {
+ return false;
+ }
+
+ // state check
+ TaskContainsKeywordPredicate e = (TaskContainsKeywordPredicate) other;
+ return keywords.equals(e.keywords);
+ }
+}
diff --git a/src/main/java/seedu/address/model/tasks/TaskDateTimeComparator.java b/src/main/java/seedu/address/model/tasks/TaskDateTimeComparator.java
new file mode 100644
index 00000000000..4b35bd60e17
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/TaskDateTimeComparator.java
@@ -0,0 +1,27 @@
+package seedu.address.model.tasks;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.Comparator;
+
+public class TaskDateTimeComparator implements Comparator {
+ @Override
+ public int compare(Task o1, Task o2) {
+ LocalDate o1Date = LocalDate.parse(o1.getDate().value);
+ LocalDate o2Date = LocalDate.parse(o2.getDate().value);
+ if (o1Date.isBefore(o2Date)) {
+ return -1;
+ } else if (o1Date.isAfter(o2Date)) {
+ return 1;
+ } else {
+ LocalTime o1Time = LocalTime.parse(o1.getTime().value);
+ LocalTime o2Time = LocalTime.parse(o2.getTime().value);
+ if (o1Time.isBefore(o2Time)) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/address/model/tasks/UniqueTaskList.java b/src/main/java/seedu/address/model/tasks/UniqueTaskList.java
new file mode 100644
index 00000000000..35d4aa3a206
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/UniqueTaskList.java
@@ -0,0 +1,154 @@
+package seedu.address.model.tasks;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.tasks.exceptions.DuplicateTaskException;
+import seedu.address.model.tasks.exceptions.TaskNotFoundException;
+
+/**
+ * A list of tasks that enforces uniqueness between its elements and does not allow nulls.
+ * A task is considered unique by comparing using {@code Task#isSameTask(Task)}.
+ * As such, adding and updating of Tasks uses Task#isSameTask(Task)
+ * for equality so as to ensure that the task being added or updated is unique in terms of
+ * identity in the UniqueTaskList. However, the removal of a task uses Task#equals(Object)
+ * so as to ensure that the task with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Task#isSameTask(Task)
+ */
+public class UniqueTaskList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent task as the given argument.
+ */
+ public boolean contains(Task toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameTask);
+ }
+
+ /**
+ * Adds a task to the list.
+ * The task must not already exist in the list.
+ * @throws Exception
+ */
+ public void add(Task toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateTaskException();
+ }
+ internalList.add(toAdd);
+ sortTasks();
+ }
+
+ /**
+ * Replaces the task {@code target} in the list with {@code editedTask}.
+ * {@code target} must exist in the list.
+ * The task identity of {@code editedTask} must not be the same as another existing task in the list.
+ */
+ public void setTask(Task target, Task editedTask) {
+ requireAllNonNull(target, editedTask);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new TaskNotFoundException();
+ }
+
+ if (!target.isSameTask(editedTask) && contains(editedTask)) {
+ throw new DuplicateTaskException();
+ }
+
+ internalList.set(index, editedTask);
+ sortTasks();
+ }
+
+ /**
+ * Removes the equivalent task from the list.
+ * The task must exist in the list.
+ * @throws Exception
+ */
+ public void remove(Task toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new TaskNotFoundException();
+ }
+ sortTasks();
+ }
+
+ public void sortTasks() {
+ internalList.sort(new TaskDateTimeComparator());
+ }
+
+ public void clear() {
+ internalList.clear();
+ }
+
+ public void setTasks(UniqueTaskList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ sortTasks();
+ }
+ /**
+ * Replaces the contents of this list with {@code tasks}.
+ * {@code tasks} must not contain duplicate tasks.
+ */
+ public void setTasks(List tasks) {
+ requireAllNonNull(tasks);
+ if (!tasksAreUnique(tasks)) {
+ throw new DuplicateTaskException();
+ }
+
+ internalList.setAll(tasks);
+ sortTasks();
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof UniqueTaskList // instanceof handles nulls
+ && internalList.equals(((UniqueTaskList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code tasks} contains only unique tasks.
+ */
+ private boolean tasksAreUnique(List tasks) {
+ for (int i = 0; i < tasks.size() - 1; i++) {
+ for (int j = i + 1; j < tasks.size(); j++) {
+ if (tasks.get(i).isSameTask(tasks.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tasks/exceptions/DuplicateTaskException.java b/src/main/java/seedu/address/model/tasks/exceptions/DuplicateTaskException.java
new file mode 100644
index 00000000000..eefc14ce361
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/exceptions/DuplicateTaskException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.tasks.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate tasks (Tasks are considered duplicates if they have the same
+ * identity).
+ */
+public class DuplicateTaskException extends RuntimeException {
+ public DuplicateTaskException() {
+ super("Operation would result in duplicate tasks");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tasks/exceptions/TaskNotFoundException.java b/src/main/java/seedu/address/model/tasks/exceptions/TaskNotFoundException.java
new file mode 100644
index 00000000000..009fa43e39a
--- /dev/null
+++ b/src/main/java/seedu/address/model/tasks/exceptions/TaskNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.address.model.tasks.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified task.
+ */
+public class TaskNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..3f0b4b1adb8 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,17 +1,20 @@
package seedu.address.model.util;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import seedu.address.model.AddressBook;
+import seedu.address.model.Date;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.Time;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.person.Stage;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
+import seedu.address.model.tasks.Task;
/**
* Contains utility methods for populating {@code AddressBook} with sample data.
@@ -19,42 +22,80 @@
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 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 Person(new Name("Alex Lee"), new Phone("87438807"), new Email("alexlee@gmail.com"),
+ new Address("30 Defu Lane 10 #04-104"), new Job("Software Engineer"),
+ new Stage("INPROGRESS")),
+ new Person(new Name("Alex Tan"), new Phone("94825832"), new Email("alext@gmail.com"),
+ new Address("1 Finlayson Green #13-00"), new Job("Data Scientist"),
+ new Stage("ACCEPTED")),
+ new Person(new Name("Alex Chan"), new Phone("82619180"), new Email("alex1996@yahoo.com"),
+ new Address("6 Ang Mo Kio Industrial Park 2"), new Job("Data Scientist"),
+ new Stage("REJECTED")),
+ new Person(new Name("Alex Lee Kai Jie"), new Phone("92462946"), new Email("alexlkj@gmail.com"),
+ new Address("76 Lorong 19 Geylang #03-01"), new Job("Data Scientist"),
+ new Stage("INPROGRESS")),
+ new Person(new Name("Steven Tan Kai Ming"), new Phone("84303712"), new Email("stevent@yahoo.com"),
+ new Address("10 Admiralty Street #01-78 North Link Building"),
+ new Job("Mobile Engineer"), new Stage("INPROGRESS")),
+ new Person(new Name("Lee Kai Jie"), new Phone("92821318"), new Email("lkj1994@gmail.com"),
+ new Address("252 Jurong East Street 24 #01-139"), new Job("Software Engineer"),
+ new Stage("ACCEPTED")),
+ new Person(new Name("Janet Tan"), new Phone("94303312"), new Email("janettan@yahoo.com"),
+ new Address("10 Admiralty Street #01-78 North Link Building"),
+ new Job("Software Developer"), new Stage("REJECTED")),
+ new Person(new Name("Lew Jia Xin"), new Phone("92573826"), new Email("lewjx@hotmail.com"),
+ new Address("261 Yishun St 22 #01-137"), new Job("Software Developer"),
+ new Stage("ACCEPTED")),
+ new Person(new Name("Tan Jia Ling"), new Phone("93375454"), new Email("tjialing@outlook.com"),
+ new Address("12 New Industrial Road #05-05 Morningstar Centre"),
+ new Job("Data Analyst"), new Stage("ACCEPTED")),
+ new Person(new Name("Zhou Jia Ling"), new Phone("92462146"), new Email("jialingz@hotmail.com"),
+ new Address("80 Marine Parade Rd #21-08"), new Job("Software Engineer"),
+ new Stage("INPROGRESS"))
+ };
+ }
+
+ public static Interview[] getSampleInterview(Person[] persons) {
+ return new Interview[] {
+ new Interview(persons[0], new Date("2022-01-20"), new Time("17:01")),
+ new Interview(persons[1], new Date("2022-01-22"), new Time("16:02")),
+ new Interview(persons[2], new Date("2022-01-24"), new Time("15:03")),
+ new Interview(persons[3], new Date("2022-01-28"), new Time("14:04")),
+ new Interview(persons[4], new Date("2022-01-17"), new Time("13:05"))
};
}
+ public static Task[] getSampleTasks() {
+ return new Task[] {
+ new Task(new Header("Add interview slots"), new Date("2022-01-09"),
+ new Time("09:10"), new Information("Add all interviews happening in the following week")),
+ new Task(new Header("Update applicants statuses"), new Date("2022-01-19"),
+ new Time("19:10"), new Information("Update all applicants statuses")),
+ new Task(new Header("Write report"), new Date("2022-02-01"),
+ new Time("18:20"), new Information("Finish up writing annual report")),
+ };
+ }
+
+
public static ReadOnlyAddressBook getSampleAddressBook() {
AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
+ Person[] samplePersons = getSamplePersons();
+ Interview[] sampleInterviews = getSampleInterview(samplePersons);
+ Task[] sampleTasks = getSampleTasks();
+
+ for (Person samplePerson : samplePersons) {
sampleAb.addPerson(samplePerson);
}
- return sampleAb;
- }
- /**
- * Returns a tag set containing the list of strings given.
- */
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
+ for (Interview sampleInterview : sampleInterviews) {
+ sampleAb.addInterview(sampleInterview);
+ }
+
+ for (Task sampleTask : sampleTasks) {
+ sampleAb.addTask(sampleTask);
+ }
+
+ return sampleAb;
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedInterview.java b/src/main/java/seedu/address/storage/JsonAdaptedInterview.java
new file mode 100644
index 00000000000..355b4852c1f
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedInterview.java
@@ -0,0 +1,72 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.person.Person;
+
+/**
+ * Jackson-friendly version of {@link Interview}.
+ */
+public class JsonAdaptedInterview {
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Interview's %s field is missing!";
+
+ private final JsonAdaptedPerson person;
+ private final String date;
+ private final String time;
+
+ /**
+ * Constructs a {@code JsonAdaptedInterview} with the given interview details.
+ */
+ @JsonCreator
+ public JsonAdaptedInterview(@JsonProperty("person") JsonAdaptedPerson person,
+ @JsonProperty("date") String date, @JsonProperty("time") String time) {
+ this.person = person;
+ this.date = date;
+ this.time = time;
+ }
+
+ /**
+ * Converts a given {@code Interview} into this class for Jackson use.
+ */
+ public JsonAdaptedInterview(Interview source) {
+ person = new JsonAdaptedPerson(source.getPerson());
+ date = source.getDate().value;
+ time = source.getTime().value;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted interview object into the model's {@code Interview} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted interview.
+ */
+ public Interview toModelType() throws IllegalValueException {
+ if (person == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "INDEX"));
+ }
+
+ final Person modelPerson = person.toModelType();
+
+ if (date == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName()));
+ }
+ if (!Date.isValidDate(date)) {
+ throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS);
+ }
+ final Date modelDate = new Date(date);
+
+ if (time == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Time.class.getSimpleName()));
+ }
+ if (!Time.isValidTime(time)) {
+ throw new IllegalValueException(Time.MESSAGE_CONSTRAINTS);
+ }
+ final Time modelTime = new Time(time);
+
+ return new Interview(modelPerson, modelDate, modelTime);
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index a6321cec2ea..aa814bbafa1 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -1,49 +1,46 @@
package seedu.address.storage;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Job;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.person.Stage;
+
/**
* Jackson-friendly version of {@link Person}.
*/
class JsonAdaptedPerson {
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Applicant's %s field is missing!";
private final String name;
private final String phone;
private final String email;
private final String address;
- private final List tagged = new ArrayList<>();
+ private final String job;
+ private final String stage;
/**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
+ * Constructs a {@code JsonAdaptedPerson} with the given applicant details.
*/
@JsonCreator
public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
@JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tagged") List tagged) {
+ @JsonProperty("job") String job, @JsonProperty("stage") String stage) {
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
- if (tagged != null) {
- this.tagged.addAll(tagged);
- }
+ this.job = job;
+ this.stage = stage;
+
}
/**
@@ -54,22 +51,17 @@ public JsonAdaptedPerson(Person source) {
phone = source.getPhone().value;
email = source.getEmail().value;
address = source.getAddress().value;
- tagged.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
+ job = source.getJob().jobTitle;
+ stage = source.getStage().value;
+
}
/**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
+ * Converts this Jackson-friendly adapted applicant object into the model's {@code Person} object.
*
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
+ * @throws IllegalValueException if there were any data constraints violated in the adapted applicant.
*/
public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tagged) {
- personTags.add(tag.toModelType());
- }
-
if (name == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
}
@@ -102,8 +94,25 @@ public Person toModelType() throws IllegalValueException {
}
final Address modelAddress = new Address(address);
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
+ if (job == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Job.class.getSimpleName()));
+ }
+ if (!Job.isValidJob(job)) {
+ throw new IllegalValueException(Job.MESSAGE_CONSTRAINTS);
+ }
+ final Job modelJob = new Job(job);
+
+ if (stage == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Stage.class.getSimpleName()));
+ }
+ if (!Stage.isValidStage(stage)) {
+ throw new IllegalValueException(Stage.MESSAGE_CONSTRAINTS);
+ }
+ final Stage modelStage = new Stage(stage);
+
+
+
+ return new Person(modelName, modelPhone, modelEmail, modelAddress, modelJob, modelStage);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
deleted file mode 100644
index 0df22bdb754..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ /dev/null
@@ -1,48 +0,0 @@
-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.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Tag}.
- */
-class JsonAdaptedTag {
-
- private final String tagName;
-
- /**
- * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
- */
- @JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
- }
-
- /**
- * Converts a given {@code Tag} into this class for Jackson use.
- */
- public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
- }
-
- @JsonValue
- public String getTagName() {
- return tagName;
- }
-
- /**
- * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
- */
- public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
- throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(tagName);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java
new file mode 100644
index 00000000000..fe7861f21f4
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java
@@ -0,0 +1,93 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.Date;
+import seedu.address.model.Time;
+import seedu.address.model.tasks.Header;
+import seedu.address.model.tasks.Information;
+import seedu.address.model.tasks.Task;
+
+
+/**
+ * JSON-friendly version of {@link Task}
+ */
+public class JsonAdaptedTask {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Task's %s field is missing!";
+
+ private final String header;
+ private final String date;
+ private final String time;
+ private final String information;
+
+ /**
+ * Constructs a {@code JsonAdaptedTask} with the given task details.
+ */
+ @JsonCreator
+ public JsonAdaptedTask(@JsonProperty("header") String header, @JsonProperty("date") String date,
+ @JsonProperty("time") String time, @JsonProperty("information") String information) {
+ this.header = header;
+ this.date = date;
+ this.time = time;
+ this.information = information;
+ }
+
+ /**
+ * Converts a given {@code Task} into this class for Jackson use.
+ */
+ public JsonAdaptedTask(Task source) {
+ header = source.getHeader().fullHeader;
+ date = source.getDate().value;
+ time = source.getTime().value;
+ information = source.getInformation().fullInformation;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted task object into the model's {@code Task} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted task.
+ */
+ public Task toModelType() throws IllegalValueException {
+
+ if (header == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Header.class.getSimpleName()));
+ }
+
+ if (!Header.isValidHeader(header)) {
+ throw new IllegalValueException(Information.MESSAGE_CONSTRAINTS);
+ }
+ final Header modelHeader = new Header(header);
+
+ if (information == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Information.class.getSimpleName()));
+ }
+
+ if (!Information.isValidInformation(information)) {
+ throw new IllegalValueException(Information.MESSAGE_CONSTRAINTS);
+ }
+ final Information modelInformation = new Information(information);
+
+ if (date == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName()));
+ }
+ if (!Date.isValidDate(date)) {
+ throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS);
+ }
+ final Date modelDate = new Date(date);
+
+ if (time == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Time.class.getSimpleName()));
+ }
+ if (!Time.isValidTime(time)) {
+ throw new IllegalValueException(Time.MESSAGE_CONSTRAINTS);
+ }
+ final Time modelTime = new Time(time);
+
+ return new Task(modelHeader, modelDate, modelTime, modelInformation);
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
index 5efd834091d..0c87511c69b 100644
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
@@ -11,7 +11,11 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
+
+
/**
* An Immutable AddressBook that is serializable to JSON format.
@@ -19,34 +23,45 @@
@JsonRootName(value = "addressbook")
class JsonSerializableAddressBook {
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
+ public static final String MESSAGE_DUPLICATE_PERSON = "Applicant list contains duplicate applicant(s).";
+ public static final String MESSAGE_DUPLICATE_INTERVIEW = "Interview list contains duplicate interview(s).";
+ public static final String MESSAGE_DUPLICATE_TASK = "Task list contains duplicate task(s).";
+ public static final String MESSAGE_NONEXISTENT_PERSON = "%s does not exist in database";
private final List persons = new ArrayList<>();
+ private final List interviews = new ArrayList<>();
+ private final List tasks = new ArrayList<>();
/**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
+ * Constructs a {@code JsonSerializableAddressBook} with the given applicants and interviews and tasks.
*/
@JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
+ public JsonSerializableAddressBook(@JsonProperty("persons") List persons,
+ @JsonProperty("interviews") List interviews,
+ @JsonProperty("tasks") List tasks) {
this.persons.addAll(persons);
+ this.interviews.addAll(interviews);
+ this.tasks.addAll(tasks);
}
/**
* Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
* @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
*/
public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
+ interviews.addAll(source.getInterviewList().stream()
+ .map(JsonAdaptedInterview::new).collect(Collectors.toList()));
+ tasks.addAll(source.getTaskList().stream().map(JsonAdaptedTask::new).collect(Collectors.toList()));
}
/**
* Converts this address book into the model's {@code AddressBook} object.
- *
* @throws IllegalValueException if there were any data constraints violated.
*/
public AddressBook toModelType() throws IllegalValueException {
AddressBook addressBook = new AddressBook();
+
for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
Person person = jsonAdaptedPerson.toModelType();
if (addressBook.hasPerson(person)) {
@@ -54,6 +69,23 @@ public AddressBook toModelType() throws IllegalValueException {
}
addressBook.addPerson(person);
}
+
+ for (JsonAdaptedInterview jsonAdaptedInterview : interviews) {
+ Interview interview = jsonAdaptedInterview.toModelType();
+ if (addressBook.hasInterview(interview)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_INTERVIEW);
+ }
+ addressBook.addInterview(interview);
+ }
+
+ for (JsonAdaptedTask jsonAdaptedTask : tasks) {
+ Task task = jsonAdaptedTask.toModelType();
+ if (addressBook.hasTask(task)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_TASK);
+ }
+ addressBook.addTask(task);
+ }
+
return addressBook;
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 9a665915949..77152a6b351 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,8 +15,25 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
- public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
+ public static final String USERGUIDE_URL = "https://ay2122s2-cs2103t-w11-2.github.io/tp/UserGuide.html";
+
+ private static final String FLAGS_HELP = "Flags:\n"
+ + "\ta/ : Address\n"
+ + "\td/ : Date (Format: yyyy-mm-dd)\n"
+ + "\te/ : Email\n"
+ + "\tg/ : Search Term (Used for grouping together search terms)\n"
+ + "\th/ : Header (task header)\n"
+ + "\ti/ : Information (task information)\n"
+ + "\tj/ : Job Position\n"
+ + "\tn/ : Name\n"
+ + "\tp/ : Phone Number\n"
+ + "\ts/ : Stage (Current progress of the job application process)\n"
+ + "\tt/ : Time (Format: HH:MM)";
+
+ public static final String HELP_MESSAGE = "Refer to the user guide for more information: "
+ + USERGUIDE_URL
+ + "\n\n"
+ + FLAGS_HELP;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
diff --git a/src/main/java/seedu/address/ui/InterviewCard.java b/src/main/java/seedu/address/ui/InterviewCard.java
new file mode 100644
index 00000000000..04189ccd5c7
--- /dev/null
+++ b/src/main/java/seedu/address/ui/InterviewCard.java
@@ -0,0 +1,132 @@
+package seedu.address.ui;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.interview.Interview;
+import seedu.address.model.person.Person;
+
+/**
+ * An UI component that displays information of a {@code Interview}.
+ */
+public class InterviewCard extends UiPart {
+
+ private static final String FXML = "InterviewListCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Interview interview;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private Label date;
+ @FXML
+ private Label time;
+ @FXML
+ private Label job;
+ @FXML
+ private Label stage;
+ @FXML
+ private Label phone;
+ @FXML
+ private Label email;
+
+ /**
+ * Creates a {@code InterviewCode} with the given {@code Interview} and index to display.
+ */
+ public InterviewCard(Interview interview, int displayedIndex) {
+ super(FXML);
+ this.interview = interview;
+ id.setText(displayedIndex + ". ");
+ Person person = interview.getPerson();
+ name.setText(person.getName().fullName);
+ String formattedDate = formatDate(interview);
+ date.setText(formattedDate);
+ String formattedTime = formatTime(interview);
+ time.setText("@ " + formattedTime);
+ job.setText(person.getJob().jobTitle);
+ stage.setText(person.getStage().value);
+ editStageStyle(stage, person);
+ phone.setText(person.getPhone().value);
+ email.setText(person.getEmail().value);
+ }
+
+ /**
+ * Format date to display in the correct format
+ *
+ * @param interview interview
+ * @return date in correct format
+ */
+ public String formatDate(Interview interview) {
+ String[] dateSplit = interview.getDate().value.split("-");
+ LocalDate parsedDate = LocalDate.parse(interview.getDate().value);
+ String formattedMonth = parsedDate.format(DateTimeFormatter.ofPattern("MMM"));
+ String formattedDate = dateSplit[2] + " " + formattedMonth + " " + dateSplit[0];
+ return formattedDate;
+ }
+
+ /**
+ * Format time to display in correct format
+ *
+ * @param interview interview
+ * @return time in correct format
+ */
+ public String formatTime(Interview interview) {
+ String[] timeSplit = interview.getTime().value.split(":");
+ LocalTime parsedTime = LocalTime.parse(timeSplit[0] + timeSplit[1], DateTimeFormatter.ofPattern("HHmm"));
+ String formattedTime = parsedTime.format(DateTimeFormatter.ofPattern("hh:mma"));
+ return formattedTime;
+ }
+
+ /**
+ * Edit style of stage
+ *
+ * @param label stage label
+ * @param person applicant
+ */
+ public void editStageStyle(Label label, Person person) {
+ if (person.getStage().value.equals("INPROGRESS")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #d2691e; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ } else if (person.getStage().value.equals("ACCEPTED")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #228b22; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ } else if (person.getStage().value.equals("REJECTED")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #b22222; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+ // instanceof handles nulls
+ if (!(other instanceof InterviewCard)) {
+ return false;
+ }
+
+ // state check
+ InterviewCard card = (InterviewCard) other;
+ return id.getText().equals(card.id.getText())
+ && interview.equals(card.interview);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/InterviewListPanel.java b/src/main/java/seedu/address/ui/InterviewListPanel.java
new file mode 100644
index 00000000000..95d140d8ebe
--- /dev/null
+++ b/src/main/java/seedu/address/ui/InterviewListPanel.java
@@ -0,0 +1,45 @@
+package seedu.address.ui;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.model.interview.Interview;
+
+/**
+ * Panel containing the list of interviews.
+ */
+public class InterviewListPanel extends UiPart {
+ private static final String FXML = "InterviewListPanel.fxml";
+
+ @FXML
+ private ListView interviewListView;
+
+ /**
+ * Creates a {@code InterviewListPanel} with the given {@code ObservableList}.
+ */
+ public InterviewListPanel(ObservableList interviewList) {
+ super(FXML);
+ interviewListView.setItems(interviewList);
+ interviewListView.setCellFactory(listView -> new InterviewListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code interview} using a {@code InterviewCard}.
+ */
+ class InterviewListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Interview interview, boolean empty) {
+ super.updateItem(interview, empty);
+
+ if (empty || interview == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new InterviewCard(interview, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 9106c3aa6e5..b4f05678542 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -1,10 +1,17 @@
package seedu.address.ui;
+import static seedu.address.logic.parser.Type.INTERVIEW;
+import static seedu.address.logic.parser.Type.PERSON;
+import static seedu.address.logic.parser.Type.TASK;
+
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.MenuItem;
+import javafx.scene.control.SingleSelectionModel;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
@@ -15,6 +22,7 @@
import seedu.address.logic.Logic;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.Type;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -32,6 +40,8 @@ public class MainWindow extends UiPart {
// Independent Ui parts residing in this Ui container
private PersonListPanel personListPanel;
+ private InterviewListPanel interviewListPanel;
+ private TaskListPanel taskListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
@@ -44,12 +54,21 @@ public class MainWindow extends UiPart {
@FXML
private StackPane personListPanelPlaceholder;
+ @FXML
+ private StackPane interviewListPanelPlaceholder;
+
+ @FXML
+ private StackPane taskListPanelPlaceHolder;
+
@FXML
private StackPane resultDisplayPlaceholder;
@FXML
private StackPane statusbarPlaceholder;
+ @FXML
+ private TabPane tabs;
+
/**
* Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
*/
@@ -113,6 +132,12 @@ void fillInnerParts() {
personListPanel = new PersonListPanel(logic.getFilteredPersonList());
personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ interviewListPanel = new InterviewListPanel(logic.getFilteredInterviewList());
+ interviewListPanelPlaceholder.getChildren().add(interviewListPanel.getRoot());
+
+ taskListPanel = new TaskListPanel(logic.getFilteredTaskList());
+ taskListPanelPlaceHolder.getChildren().add(taskListPanel.getRoot());
+
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
@@ -186,6 +211,8 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleExit();
}
+ changeTab(commandResult.getType());
+
return commandResult;
} catch (CommandException | ParseException e) {
logger.info("Invalid command: " + commandText);
@@ -193,4 +220,19 @@ private CommandResult executeCommand(String commandText) throws CommandException
throw e;
}
}
+
+ /**
+ * Toggle between different tabs based on type of command given
+ * @param type type of command
+ */
+ public void changeTab(Type type) {
+ SingleSelectionModel selectionModel = tabs.getSelectionModel();
+ if (type == PERSON) {
+ selectionModel.select(0);
+ } else if (type == INTERVIEW) {
+ selectionModel.select(1);
+ } else if (type == TASK) {
+ selectionModel.select(2);
+ }
+ }
}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 7fc927bc5d9..c900f828917 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -1,10 +1,7 @@
package seedu.address.ui;
-import java.util.Comparator;
-
import javafx.fxml.FXML;
import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import seedu.address.model.person.Person;
@@ -39,7 +36,9 @@ public class PersonCard extends UiPart {
@FXML
private Label email;
@FXML
- private FlowPane tags;
+ private Label job;
+ @FXML
+ private Label stage;
/**
* Creates a {@code PersonCode} with the given {@code Person} and index to display.
@@ -52,9 +51,28 @@ public PersonCard(Person person, int displayedIndex) {
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ job.setText(person.getJob().jobTitle);
+ stage.setText(person.getStage().value);
+ editStageStyle(stage, person);
+ }
+
+ /**
+ * Edit style of stage
+ *
+ * @param label stage label
+ * @param person applicant
+ */
+ public void editStageStyle(Label label, Person person) {
+ if (person.getStage().value.equals("INPROGRESS")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #d2691e; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ } else if (person.getStage().value.equals("ACCEPTED")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #228b22; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ } else if (person.getStage().value.equals("REJECTED")) {
+ stage.setStyle("-fx-text-fill: white; -fx-background-color: #b22222; -fx-padding: 1 3 1 3; "
+ + "-fx-border-radius: 2; -fx-background-radius: 2; -fx-font-size: 11;");
+ }
}
@Override
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
index f4c501a897b..0eec2be6fb2 100644
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ b/src/main/java/seedu/address/ui/PersonListPanel.java
@@ -1,21 +1,17 @@
package seedu.address.ui;
-import java.util.logging.Logger;
-
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
/**
- * Panel containing the list of persons.
+ * Panel containing the list of applicants.
*/
public class PersonListPanel extends UiPart {
private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
@FXML
private ListView personListView;
diff --git a/src/main/java/seedu/address/ui/TaskCard.java b/src/main/java/seedu/address/ui/TaskCard.java
new file mode 100644
index 00000000000..fa3ed815c53
--- /dev/null
+++ b/src/main/java/seedu/address/ui/TaskCard.java
@@ -0,0 +1,98 @@
+package seedu.address.ui;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.tasks.Task;
+
+public class TaskCard extends UiPart {
+
+ private static final String FXML = "TaskListCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Task task;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label id;
+ @FXML
+ private Label header;
+ @FXML
+ private Label information;
+ @FXML
+ private Label date;
+ @FXML
+ private Label time;
+
+ /**
+ * Creates a {@code TaskCode} with the given {@code Task} and index to display.
+ */
+ public TaskCard(Task task, int displayedIndex) {
+ super(FXML);
+ this.task = task;
+ id.setText(displayedIndex + ". ");
+ header.setText(task.getHeader().fullHeader);
+ information.setText(task.getInformation().fullInformation);
+ String formattedDate = formatDate(task);
+ date.setText("Date: " + formattedDate);
+ String formattedTime = formatTime(task);
+ time.setText("Time: " + formattedTime);
+ }
+
+ /**
+ * Format date to display in correct format
+ *
+ * @param task task
+ * @return date in correct format
+ */
+ public String formatDate(Task task) {
+ String[] dateSplit = task.getDate().value.split("-");
+ LocalDate parsedDate = LocalDate.parse(task.getDate().value);
+ String formattedMonth = parsedDate.format(DateTimeFormatter.ofPattern("MMM"));
+ String formattedDate = dateSplit[2] + " " + formattedMonth + " " + dateSplit[0];
+ return formattedDate;
+ }
+
+ /**
+ * Format time to display in correct format
+ *
+ * @param task task
+ * @return time in correct format
+ */
+ public String formatTime(Task task) {
+ String[] timeSplit = task.getTime().value.split(":");
+ LocalTime parsedTime = LocalTime.parse(timeSplit[0] + timeSplit[1], DateTimeFormatter.ofPattern("HHmm"));
+ String formattedTime = parsedTime.format(DateTimeFormatter.ofPattern("hh:mma"));
+ return formattedTime;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+ // instanceof handles nulls
+ if (!(other instanceof TaskCard)) {
+ return false;
+ }
+
+ // state check
+ TaskCard card = (TaskCard) other;
+ return id.getText().equals(card.id.getText())
+ && task.equals(card.task);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/TaskListPanel.java b/src/main/java/seedu/address/ui/TaskListPanel.java
new file mode 100644
index 00000000000..9d5fac076f6
--- /dev/null
+++ b/src/main/java/seedu/address/ui/TaskListPanel.java
@@ -0,0 +1,45 @@
+package seedu.address.ui;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.model.tasks.Task;
+
+/**
+ * Panel containing the list of tasks.
+ */
+public class TaskListPanel extends UiPart {
+
+ private static final String FXML = "TaskListPanel.fxml";
+
+ @FXML
+ private ListView taskListView;
+
+ /**
+ * Creates a {@code TaskListPanel} with the given {@code ObservableList}.
+ */
+ public TaskListPanel(ObservableList taskList) {
+ super(FXML);
+ taskListView.setItems(taskList);
+ taskListView.setCellFactory(listView -> new TaskListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Task} using a {@code TaskCard}.
+ */
+ class TaskListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Task task, boolean empty) {
+ super.updateItem(task, empty);
+
+ if (empty || task == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new TaskCard(task, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java
index fdf024138bc..eac5c90eff2 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/seedu/address/ui/UiManager.java
@@ -36,14 +36,13 @@ public UiManager(Logic logic) {
public void start(Stage primaryStage) {
logger.info("Starting UI...");
- //Set the application icon.
+ // Set the application icon.
primaryStage.getIcons().add(getImage(ICON_APPLICATION));
try {
mainWindow = new MainWindow(primaryStage, logic);
- mainWindow.show(); //This should be called before creating other UI parts
+ mainWindow.show(); // This should be called before creating other UI parts
mainWindow.fillInnerParts();
-
} catch (Throwable e) {
logger.severe(StringUtil.getDetails(e));
showFatalErrorDialogAndShutdown("Fatal error during initializing", e);
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..4024f496c40 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -336,17 +336,3 @@
-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: #3e7b91;
- -fx-padding: 1 3 1 3;
- -fx-border-radius: 2;
- -fx-background-radius: 2;
- -fx-font-size: 11;
-}
diff --git a/src/main/resources/view/InterviewListCard.fxml b/src/main/resources/view/InterviewListCard.fxml
new file mode 100644
index 00000000000..7da854018cb
--- /dev/null
+++ b/src/main/resources/view/InterviewListCard.fxml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/InterviewListPanel.fxml b/src/main/resources/view/InterviewListPanel.fxml
new file mode 100644
index 00000000000..a7b559aa9d8
--- /dev/null
+++ b/src/main/resources/view/InterviewListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index a431648f6c0..3851dd8a664 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -6,13 +6,14 @@
-
+
+
+ title="HRConnect" minWidth="450" minHeight="600" onCloseRequest="#handleExit">
@@ -46,13 +47,32 @@
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index f08ea32ad55..f8edb3ea26f 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -3,7 +3,6 @@
-
@@ -27,7 +26,12 @@
-
+
+
+
+
+
diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml
new file mode 100644
index 00000000000..a56ca965652
--- /dev/null
+++ b/src/main/resources/view/TaskListCard.fxml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/TaskListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml
new file mode 100644
index 00000000000..a58887c89d1
--- /dev/null
+++ b/src/main/resources/view/TaskListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/test/data/CsvTest/all_correct.csv b/src/test/data/CsvTest/all_correct.csv
new file mode 100644
index 00000000000..8e972b5548e
--- /dev/null
+++ b/src/test/data/CsvTest/all_correct.csv
@@ -0,0 +1,30 @@
+Alejandro Sharma 56564367 alejandros@gmail.com 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer ACCEPTED
+Elly Beattie 62888566 ellyb@yahoo.com 94 Littleton Lane Rocky Mount, NC 27804 Computer Hardware Engineer REJECTED
+Kajus Holcomb 89711048 kajush@gmail.com 8262 Longbranch St. Uniontown, PA 15401 Software Developer REJECTED
+Ellis Curran 85538213 ellisc@yahoo.com 113 West Euclid Drive Delray Beach, FL 33445 Computer Systems Analyst ACCEPTED
+Leopold Jacobson 59973763 leopoldj@gmail.com 7082 Purple Finch Dr. La Porte, IN 46350 Computer Hardware Engineer INPROGRESS
+Ayesha East 82920728 ayeshae@outlook.com 219 Wagon Court Rosedale, NY 11422 Computer Systems Analyst INPROGRESS
+Hadley Warner 40643544 hadleyw@yahoo.com 8 Edgewood St. North Brunswick, NJ 08902 Software Developer REJECTED
+Joni Marshall 77992558 jonim@gmail.com 616 Smith St. Potomac, MD 20854 Computer Systems Analyst REJECTED
+Zakaria Mcneil 61681358 zakariam@yahoo.com 7977 Somerset Ave. Milwaukee, WI 53204 Software Developer INPROGRESS
+Prisha Mcbride 68997369 prisham@gmail.com 113 North Rock Creek Ave. Indiana, PA 15701 Database administrator ACCEPTED
+Zakir Arnold 41183506 zakira@outlook.com 7840 Rosewood Street Solon, OH 44139 Computer Systems Analyst INPROGRESS
+Ahmet Clements 39902818 ahmetc@gmail.com 30 Sunset Dr. Southaven, MS 38671 Software Developer REJECTED
+Alana Hirst 27421820 alanah@yahoo.com 7 East Birch Hill Rd. Sevierville, TN 37876 Computer Hardware Engineer INPROGRESS
+Claude Higgs 69000340 claudeh@gmail.com 8776 West River St. Hendersonville, NC 28792 Computer Systems Analyst REJECTED
+Melanie Quintana 70216324 melanieq@outlook.com 41 Glenlake St. Hamilton, OH 45011 Computer Hardware Engineer INPROGRESS
+Clive Hurley 30679562 cliveh@gmail.com 608 County Lane Macon, GA 31204 Database administrator ACCEPTED
+Angel Beach 26238340 angelb@outlook.com 2 Southampton Lane Ithaca, NY 14850 Software Developer INPROGRESS
+Keziah Ayala 27240526 keziaha@yahoo.com 7051 Maiden Dr. West Des Moines, IA 50265 Computer Systems Analyst ACCEPTED
+Harlow Mcgill 27628227 harlowm@gmail.com 243 Shirley Street Natchez, MS 39120 Computer Hardware Engineer INPROGRESS
+Blake Lott 48792242 blakel@gmail.com 465 Shub Farm St. Casselberry, FL 32707 Database administrator INPROGRESS
+Cleveland Lowe 82483944 clevelandl@gmail.com 494 South Cleveland Rd. Marion, NC 28752 Software Developer REJECTED
+Mahdi Nieves 61964570 mahdin@gmail.com 535 Lake Lane Nampa, ID 83651 Computer Systems Analyst ACCEPTED
+Nella Mathews 71975412 nellam@yahoo.com 9352 New St. Ellenwood, GA 30294 Database administrator INPROGRESS
+Zaine Diaz 89051558 zained@outlook.com 498 Honey Creek Ave. Silver Spring, MD 20901 Computer Hardware Engineer INPROGRESS
+Daniaal Easton 53502276 daniaale@gmail.com 650 Country Club Street Buckeye, AZ 85326 Computer Systems Analyst INPROGRESS
+Shoaib Cuevas 85284994 shoaibc@outlook.com 9298 New Saddle Ave. Brick, NJ 08723 Software Developer INPROGRESS
+Georga Estrada 72561154 georgae@yahoo.com 48 Bald Hill Ave. Valrico, FL 33594 Database administrator ACCEPTED
+Sarah Nelson 14579306 sarahn@outlook.com 132 Lakewood St. Mahwah, NJ 07430 Computer Systems Analyst INPROGRESS
+Leyton Mcclure 88002790 leytonm@yahoo.com 65 North Wild Horse Lane Gurnee, IL 60031 Computer Hardware Engineer REJECTED
+Kian Handley 15968569 kianh@yahoo.com 850 Birchwood Ave. New Port Richey, FL 34653 Computer Hardware Engineer INPROGRESS
diff --git a/src/test/data/CsvTest/excess_fields.csv b/src/test/data/CsvTest/excess_fields.csv
new file mode 100644
index 00000000000..6fd96afdc03
--- /dev/null
+++ b/src/test/data/CsvTest/excess_fields.csv
@@ -0,0 +1 @@
+Alejandro Sharma 56564367 alejandros@gmail.com 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer ACCEPTED wrong
diff --git a/src/test/data/CsvTest/excess_whitespace.csv b/src/test/data/CsvTest/excess_whitespace.csv
new file mode 100644
index 00000000000..7b4f0d8e670
--- /dev/null
+++ b/src/test/data/CsvTest/excess_whitespace.csv
@@ -0,0 +1,2 @@
+Alejandro Sharma 56564367 alejandros@gmail.com 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer ACCEPTED
+Elly Beattie 62888566 ellyb@yahoo.com 94 Littleton Lane Rocky Mount, NC 27804 Computer Hardware Engineer REJECTED
diff --git a/src/test/data/CsvTest/no_file_format b/src/test/data/CsvTest/no_file_format
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/test/data/CsvTest/overlapping_file_format.json.csv b/src/test/data/CsvTest/overlapping_file_format.json.csv
new file mode 100644
index 00000000000..5571a490826
--- /dev/null
+++ b/src/test/data/CsvTest/overlapping_file_format.json.csv
@@ -0,0 +1,2 @@
+Alejandro Sharma 56564367 alejandros@gmail.com 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer ACCEPTED
+Elly Beattie 62888566 ellyb@yahoo.com 94 Littleton Lane Rocky Mount, NC 27804 Computer Hardware Engineer REJECTED
diff --git a/src/test/data/CsvTest/too_little_fields.csv b/src/test/data/CsvTest/too_little_fields.csv
new file mode 100644
index 00000000000..e41986813dc
--- /dev/null
+++ b/src/test/data/CsvTest/too_little_fields.csv
@@ -0,0 +1 @@
+Alejandro Sharma 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer ACCEPTED
diff --git a/src/test/data/CsvTest/wrong_file_format.txt b/src/test/data/CsvTest/wrong_file_format.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/test/data/CsvTest/wrong_stage.csv b/src/test/data/CsvTest/wrong_stage.csv
new file mode 100644
index 00000000000..494938a2a85
--- /dev/null
+++ b/src/test/data/CsvTest/wrong_stage.csv
@@ -0,0 +1 @@
+Alejandro Sharma 56564367 alejandros@gmail.com 41 High Point Ave. Holly Springs, NC 27540 Computer Hardware Engineer wrong
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
index 6a4d2b7181c..c04024407e7 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
@@ -3,11 +3,15 @@
"name": "Valid Person",
"phone": "9482424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "job": "Software Engineer",
+ "stage": "INPROGRESS"
}, {
"name": "Person With Invalid Phone Field",
"phone": "948asdf2424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "job": "Software Engineer",
+ "stage": "INPROGRESS"
} ]
}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
index ccd21f7d1a9..f6f8c8e8dde 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
@@ -3,6 +3,8 @@
"name": "Person with invalid name field: Ha!ns Mu@ster",
"phone": "9482424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "job": "Software Engineer",
+ "stage": "INPROGRESS"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
index 48831cc7674..15fe7a5a21d 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
@@ -4,11 +4,14 @@
"phone": "94351253",
"email": "alice@example.com",
"address": "123, Jurong West Ave 6, #08-111",
- "tagged": [ "friends" ]
+ "job": "Software Engineer",
+ "stage": "INPROGRESS"
}, {
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "job": "Mobile Engineer",
+ "stage": "ACCEPTED"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
index ad3f135ae42..d1a3670b1be 100644
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
@@ -3,6 +3,8 @@
"name": "Hans Muster",
"phone": "9482424",
"email": "invalid@email!3e",
- "address": "4th street"
+ "address": "4th street",
+ "job": "Software Engineer",
+ "stage": "INPROGRESS"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
index f10eddee12e..ef905e8cb50 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
@@ -5,42 +5,48 @@
"phone" : "94351253",
"email" : "alice@example.com",
"address" : "123, Jurong West Ave 6, #08-111",
- "tagged" : [ "friends" ]
+ "job" : "Software Engineer",
+ "stage" : "INPROGRESS"
}, {
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
"address" : "311, Clementi Ave 2, #02-25",
- "tagged" : [ "owesMoney", "friends" ]
+ "job" : "Data Analyst",
+ "stage" : "REJECTED"
}, {
"name" : "Carl Kurz",
"phone" : "95352563",
"email" : "heinz@example.com",
- "address" : "wall street",
- "tagged" : [ ]
+ "job" : "Software Engineer",
+ "stage" : "ACCEPTED"
}, {
"name" : "Daniel Meier",
"phone" : "87652533",
"email" : "cornelia@example.com",
"address" : "10th street",
- "tagged" : [ "friends" ]
+ "job" : "Data Scientist",
+ "stage" : "INPROGRESS"
}, {
"name" : "Elle Meyer",
"phone" : "9482224",
"email" : "werner@example.com",
"address" : "michegan ave",
- "tagged" : [ ]
+ "job" : "Software Developer",
+ "stage" : "INPROGRESS"
}, {
"name" : "Fiona Kunz",
"phone" : "9482427",
"email" : "lydia@example.com",
"address" : "little tokyo",
- "tagged" : [ ]
+ "job" : "Mobile Engineer",
+ "stage" : "ACCEPTED"
}, {
"name" : "George Best",
"phone" : "9482442",
"email" : "anna@example.com",
"address" : "4th street",
- "tagged" : [ ]
+ "job" : "Software Engineer",
+ "stage" : "REJECTED"
} ]
}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index ad923ac249a..ff432aff1e6 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -5,8 +5,10 @@
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.JOB_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.STAGE_DESC_AMY;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.AMY;
@@ -20,6 +22,7 @@
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.ListPersonCommand;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
@@ -43,8 +46,8 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
- JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(
+ temporaryFolder.resolve("addressBook.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
@@ -58,30 +61,30 @@ public void execute_invalidCommandFormat_throwsParseException() {
@Test
public void execute_commandExecutionError_throwsCommandException() {
- String deleteCommand = "delete 9";
+ String deleteCommand = "delete [p] 9";
assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
@Test
public void execute_validCommand_success() throws Exception {
- String listCommand = ListCommand.COMMAND_WORD;
- assertCommandSuccess(listCommand, ListCommand.MESSAGE_SUCCESS, model);
+ String listCommand = ListCommand.COMMAND_WORD + " [p]";
+ assertCommandSuccess(listCommand, ListPersonCommand.MESSAGE_SUCCESS, model);
}
@Test
public void execute_storageThrowsIoException_throwsCommandException() {
// Setup LogicManager with JsonAddressBookIoExceptionThrowingStub
- JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookIoExceptionThrowingStub(temporaryFolder.resolve("ioExceptionAddressBook.json"));
- JsonUserPrefsStorage userPrefsStorage =
- new JsonUserPrefsStorage(temporaryFolder.resolve("ioExceptionUserPrefs.json"));
+ JsonAddressBookStorage addressBookStorage = new JsonAddressBookIoExceptionThrowingStub(
+ temporaryFolder.resolve("ioExceptionAddressBook.json"));
+ JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(
+ temporaryFolder.resolve("ioExceptionUserPrefs.json"));
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
// Execute add command
- String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY
- + ADDRESS_DESC_AMY;
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
+ String addCommand = AddCommand.COMMAND_WORD + " [p] " + NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY
+ + ADDRESS_DESC_AMY + JOB_DESC_AMY + STAGE_DESC_AMY;
+ Person expectedPerson = new PersonBuilder(AMY).build();
ModelManager expectedModel = new ModelManager();
expectedModel.addPerson(expectedPerson);
String expectedMessage = LogicManager.FILE_OPS_ERROR_MESSAGE + DUMMY_IO_EXCEPTION;
@@ -97,7 +100,8 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException
* Executes the command and confirms that
* - no exceptions are thrown
* - the feedback message is equal to {@code expectedMessage}
- * - the internal model manager state is the same as that in {@code expectedModel}
+ * - the internal model manager state is the same as that in
+ * {@code expectedModel}
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandSuccess(String inputCommand, String expectedMessage,
@@ -108,7 +112,8 @@ private void assertCommandSuccess(String inputCommand, String expectedMessage,
}
/**
- * Executes the command, confirms that a ParseException is thrown and that the result message is correct.
+ * Executes the command, confirms that a ParseException is thrown and that the
+ * result message is correct.
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertParseException(String inputCommand, String expectedMessage) {
@@ -116,7 +121,8 @@ private void assertParseException(String inputCommand, String expectedMessage) {
}
/**
- * Executes the command, confirms that a CommandException is thrown and that the result message is correct.
+ * Executes the command, confirms that a CommandException is thrown and that the
+ * result message is correct.
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandException(String inputCommand, String expectedMessage) {
@@ -124,7 +130,8 @@ private void assertCommandException(String inputCommand, String expectedMessage)
}
/**
- * Executes the command, confirms that the exception is thrown and that the result message is correct.
+ * Executes the command, confirms that the exception is thrown and that the
+ * result message is correct.
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
@@ -137,11 +144,12 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
* Executes the command and confirms that
* - the {@code expectedException} is thrown
* - the resulting error message is equal to {@code expectedMessage}
- * - the internal model manager state is the same as that in {@code expectedModel}
+ * - the internal model manager state is the same as that in
+ * {@code expectedModel}
* @see #assertCommandSuccess(String, String, Model)
*/
- private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
- String expectedMessage, Model expectedModel) {
+ private void assertCommandFailure(String inputCommand,
+ Class extends Throwable> expectedException, String expectedMessage, Model expectedModel) {
assertThrows(expectedException, expectedMessage, () -> logic.execute(inputCommand));
assertEquals(expectedModel, model);
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddPersonCommandIntegrationTest.java
similarity index 77%
rename from src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
rename to src/test/java/seedu/address/logic/commands/AddPersonCommandIntegrationTest.java
index cb8714bb055..dc5fae28edc 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddPersonCommandIntegrationTest.java
@@ -14,9 +14,9 @@
import seedu.address.testutil.PersonBuilder;
/**
- * Contains integration tests (interaction with the Model) for {@code AddCommand}.
+ * Contains integration tests (interaction with the Model) for {@code AddPersonCommand}.
*/
-public class AddCommandIntegrationTest {
+public class AddPersonCommandIntegrationTest {
private Model model;
@@ -32,14 +32,14 @@ public void execute_newPerson_success() {
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.addPerson(validPerson);
- assertCommandSuccess(new AddCommand(validPerson), model,
- String.format(AddCommand.MESSAGE_SUCCESS, validPerson), expectedModel);
+ assertCommandSuccess(new AddPersonCommand(validPerson), model,
+ String.format(AddPersonCommand.MESSAGE_SUCCESS, validPerson), expectedModel);
}
@Test
public void execute_duplicatePerson_throwsCommandException() {
Person personInList = model.getAddressBook().getPersonList().get(0);
- assertCommandFailure(new AddCommand(personInList), model, AddCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(new AddPersonCommand(personInList), model, AddPersonCommand.MESSAGE_DUPLICATE_PERSON);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java
similarity index 62%
rename from src/test/java/seedu/address/logic/commands/AddCommandTest.java
rename to src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java
index 5865713d5dd..7ad164d36a5 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java
@@ -20,14 +20,16 @@
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.ReadOnlyUserPrefs;
+import seedu.address.model.interview.Interview;
import seedu.address.model.person.Person;
+import seedu.address.model.tasks.Task;
import seedu.address.testutil.PersonBuilder;
-public class AddCommandTest {
+public class AddPersonCommandTest {
@Test
public void constructor_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new AddCommand(null));
+ assertThrows(NullPointerException.class, () -> new AddPersonCommand(null));
}
@Test
@@ -35,33 +37,34 @@ public void execute_personAcceptedByModel_addSuccessful() throws Exception {
ModelStubAcceptingPersonAdded modelStub = new ModelStubAcceptingPersonAdded();
Person validPerson = new PersonBuilder().build();
- CommandResult commandResult = new AddCommand(validPerson).execute(modelStub);
+ CommandResult commandResult = new AddPersonCommand(validPerson).execute(modelStub);
- assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, validPerson), commandResult.getFeedbackToUser());
+ assertEquals(String.format(AddPersonCommand.MESSAGE_SUCCESS, validPerson), commandResult.getFeedbackToUser());
assertEquals(Arrays.asList(validPerson), modelStub.personsAdded);
}
@Test
public void execute_duplicatePerson_throwsCommandException() {
Person validPerson = new PersonBuilder().build();
- AddCommand addCommand = new AddCommand(validPerson);
+ AddCommand addCommand = new AddPersonCommand(validPerson);
ModelStub modelStub = new ModelStubWithPerson(validPerson);
- assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub));
+ assertThrows(CommandException.class, AddPersonCommand.MESSAGE_DUPLICATE_PERSON, () ->
+ addCommand.execute(modelStub));
}
@Test
public void equals() {
Person alice = new PersonBuilder().withName("Alice").build();
Person bob = new PersonBuilder().withName("Bob").build();
- AddCommand addAliceCommand = new AddCommand(alice);
- AddCommand addBobCommand = new AddCommand(bob);
+ AddCommand addAliceCommand = new AddPersonCommand(alice);
+ AddCommand addBobCommand = new AddPersonCommand(bob);
// same object -> returns true
assertTrue(addAliceCommand.equals(addAliceCommand));
// same values -> returns true
- AddCommand addAliceCommandCopy = new AddCommand(alice);
+ AddCommand addAliceCommandCopy = new AddPersonCommand(alice);
assertTrue(addAliceCommand.equals(addAliceCommandCopy));
// different types -> returns false
@@ -113,6 +116,16 @@ public void addPerson(Person person) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void addInterview(Interview interview) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void addTask(Task task) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void setAddressBook(ReadOnlyAddressBook newData) {
throw new AssertionError("This method should not be called.");
@@ -128,29 +141,97 @@ public boolean hasPerson(Person person) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public boolean hasInterview(Interview interview) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean hasTask(Task task) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void deletePerson(Person target) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void deleteInterview(Interview target) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void deleteTask(Task target) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void setPerson(Person target, Person editedPerson) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void setInterview(Interview target, Interview editedInterview) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setTask(Task target, Task editedTask) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void resetPersons() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void resetInterviews() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void resetTasks() {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public ObservableList getFilteredPersonList() {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public ObservableList getFilteredInterviewList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getFilteredTaskList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void updateFilteredPersonList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+
+ @Override
+ public void updateFilteredInterviewList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateFilteredTaskList(Predicate predicate) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+
+
}
/**
- * A Model stub that contains a single person.
+ * A Model stub that contains a single applicant.
*/
private class ModelStubWithPerson extends ModelStub {
private final Person person;
@@ -168,7 +249,7 @@ public boolean hasPerson(Person person) {
}
/**
- * A Model stub that always accept the person being added.
+ * A Model stub that always accept the applicant being added.
*/
private class ModelStubAcceptingPersonAdded extends ModelStub {
final ArrayList personsAdded = new ArrayList<>();
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
index 80d9110c03a..caa12f03b86 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
@@ -5,7 +5,6 @@
import org.junit.jupiter.api.Test;
-import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
@@ -13,20 +12,20 @@
public class ClearCommandTest {
@Test
- public void execute_emptyAddressBook_success() {
+ public void execute_emptyPersonList_success() {
Model model = new ModelManager();
Model expectedModel = new ModelManager();
- assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ClearPersonCommand(), model, ClearPersonCommand.MESSAGE_SUCCESS, expectedModel);
}
@Test
- public void execute_nonEmptyAddressBook_success() {
+ public void execute_nonEmptyPersonList_success() {
Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel.setAddressBook(new AddressBook());
+ expectedModel.resetPersons();
- assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ClearPersonCommand(), model, ClearPersonCommand.MESSAGE_SUCCESS, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
index 4f3eb46e9ef..dea0a2bc683 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
@@ -10,11 +10,11 @@
public class CommandResultTest {
@Test
public void equals() {
- CommandResult commandResult = new CommandResult("feedback");
+ CommandResult commandResult = new CommandResult("feedback", null);
// same values -> returns true
- assertTrue(commandResult.equals(new CommandResult("feedback")));
- assertTrue(commandResult.equals(new CommandResult("feedback", false, false)));
+ assertTrue(commandResult.equals(new CommandResult("feedback", null)));
+ assertTrue(commandResult.equals(new CommandResult("feedback", null, false, false)));
// same object -> returns true
assertTrue(commandResult.equals(commandResult));
@@ -26,29 +26,29 @@ public void equals() {
assertFalse(commandResult.equals(0.5f));
// different feedbackToUser value -> returns false
- assertFalse(commandResult.equals(new CommandResult("different")));
+ assertFalse(commandResult.equals(new CommandResult("different", null)));
// different showHelp value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", true, false)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", null, true, false)));
// different exit value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", false, true)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", null, false, true)));
}
@Test
public void hashcode() {
- CommandResult commandResult = new CommandResult("feedback");
+ CommandResult commandResult = new CommandResult("feedback", null);
// same values -> returns same hashcode
- assertEquals(commandResult.hashCode(), new CommandResult("feedback").hashCode());
+ assertEquals(commandResult.hashCode(), new CommandResult("feedback", null).hashCode());
// different feedbackToUser value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("different").hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("different", null).hashCode());
// different showHelp value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", null, true, false).hashCode());
// different exit value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", null, false, true).hashCode());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..472a19169fb 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -4,21 +4,21 @@
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_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STAGE;
import static seedu.address.testutil.Assert.assertThrows;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
import seedu.address.model.person.Person;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
import seedu.address.testutil.EditPersonDescriptorBuilder;
/**
@@ -34,8 +34,10 @@ 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_TAG_HUSBAND = "husband";
- public static final String VALID_TAG_FRIEND = "friend";
+ public static final String VALID_JOB_AMY = "Software Engineer";
+ public static final String VALID_JOB_BOB = "Data Scientist";
+ public static final String VALID_STAGE_AMY = "INPROGRESS";
+ public static final String VALID_STAGE_BOB = "ACCEPTED";
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
@@ -45,28 +47,32 @@ 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 TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
- public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String JOB_DESC_AMY = " " + PREFIX_JOB + VALID_JOB_AMY;
+ public static final String JOB_DESC_BOB = " " + PREFIX_JOB + VALID_JOB_BOB;
+ public static final String STAGE_DESC_AMY = " " + PREFIX_STAGE + VALID_STAGE_AMY;
+ public static final String STAGE_DESC_BOB = " " + PREFIX_STAGE + VALID_STAGE_BOB;
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_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_JOB_DESC = " " + PREFIX_JOB + "Software Engineer&"; // '&' not allowed in jobs
+ public static final String INVALID_STAGE_DESC = " " + PREFIX_STAGE + "PROCESSING"; //only 3 stages allowed in stage
+
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
- public static final EditCommand.EditPersonDescriptor DESC_AMY;
- public static final EditCommand.EditPersonDescriptor DESC_BOB;
+ public static final EditPersonCommand.EditPersonDescriptor DESC_AMY;
+ public static final EditPersonCommand.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();
+ .withJob(VALID_JOB_AMY).withStage(VALID_STAGE_AMY).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();
+ .withJob(VALID_JOB_BOB).withStage(VALID_STAGE_BOB).build();
}
/**
@@ -91,7 +97,7 @@ public static void assertCommandSuccess(Command command, Model actualModel, Comm
*/
public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage,
Model expectedModel) {
- CommandResult expectedCommandResult = new CommandResult(expectedMessage);
+ CommandResult expectedCommandResult = new CommandResult(expectedMessage, command.getType());
assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel);
}
@@ -99,7 +105,7 @@ public static void assertCommandSuccess(Command command, Model actualModel, Stri
* Executes the given {@code command}, confirms that
* - a {@code CommandException} is thrown
* - the CommandException message matches {@code expectedMessage}
- * - the address book, filtered person list and selected person in {@code actualModel} remain unchanged
+ * - the address book, filtered applicant list and selected applicant in {@code actualModel} remain unchanged
*/
public static void assertCommandFailure(Command command, Model actualModel, String expectedMessage) {
// we are unable to defensively copy the model for comparison later, so we can
@@ -112,15 +118,17 @@ public static void assertCommandFailure(Command command, Model actualModel, Stri
assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
}
/**
- * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
+ * Updates {@code model}'s filtered list to show only the applicant at the given {@code targetIndex} in the
* {@code model}'s address book.
*/
public static void showPersonAtIndex(Model model, Index targetIndex) {
assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size());
Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
- final String[] splitName = person.getName().fullName.split("\\s+");
- model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
+
+ List keywords = new ArrayList<>();
+ keywords.add("n/" + person.getName().fullName.split(" ")[0]);
+ model.updateFilteredPersonList(new PersonContainsKeywordsPredicate(keywords));
assertEquals(1, model.getFilteredPersonList().size());
}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeletePersonCommandTest.java
similarity index 69%
rename from src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
rename to src/test/java/seedu/address/logic/commands/DeletePersonCommandTest.java
index 45a8c910ba1..fe69fbadb7a 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeletePersonCommandTest.java
@@ -20,31 +20,31 @@
/**
* Contains integration tests (interaction with the Model) and unit tests for
- * {@code DeleteCommand}.
+ * {@code DeletePersonCommand}.
*/
-public class DeleteCommandTest {
+public class DeletePersonCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
@Test
public void execute_validIndexUnfilteredList_success() {
Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeletePersonCommand deletePersonCommand = new DeletePersonCommand(INDEX_FIRST_PERSON);
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
+ String expectedMessage = String.format(DeletePersonCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
- assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+ assertCommandSuccess(deletePersonCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_invalidIndexUnfilteredList_throwsCommandException() {
Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ DeletePersonCommand deletePersonCommand = new DeletePersonCommand(outOfBoundIndex);
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deletePersonCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
@Test
@@ -52,15 +52,15 @@ public void execute_validIndexFilteredList_success() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeletePersonCommand deletePersonCommand = new DeletePersonCommand(INDEX_FIRST_PERSON);
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
+ String expectedMessage = String.format(DeletePersonCommand.MESSAGE_DELETE_PERSON_SUCCESS, personToDelete);
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
showNoPerson(expectedModel);
- assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+ assertCommandSuccess(deletePersonCommand, model, expectedMessage, expectedModel);
}
@Test
@@ -71,21 +71,21 @@ public void execute_invalidIndexFilteredList_throwsCommandException() {
// ensures that outOfBoundIndex is still in bounds of address book list
assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ DeletePersonCommand deletePersonCommand = new DeletePersonCommand(outOfBoundIndex);
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deletePersonCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
@Test
public void equals() {
- DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
- DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
+ DeletePersonCommand deleteFirstCommand = new DeletePersonCommand(INDEX_FIRST_PERSON);
+ DeletePersonCommand deleteSecondCommand = new DeletePersonCommand(INDEX_SECOND_PERSON);
// same object -> returns true
assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
// same values -> returns true
- DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeletePersonCommand deleteFirstCommandCopy = new DeletePersonCommand(INDEX_FIRST_PERSON);
assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
// different types -> returns false
@@ -94,7 +94,7 @@ public void equals() {
// null -> returns false
assertFalse(deleteFirstCommand.equals(null));
- // different person -> returns false
+ // different applicant -> returns false
assertFalse(deleteFirstCommand.equals(deleteSecondCommand));
}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditPersonCommandTest.java
similarity index 73%
rename from src/test/java/seedu/address/logic/commands/EditCommandTest.java
rename to src/test/java/seedu/address/logic/commands/EditPersonCommandTest.java
index 214c6c2507b..af62346aa02 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonCommandTest.java
@@ -4,9 +4,9 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_JOB_BOB;
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_TAG_HUSBAND;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
@@ -18,7 +18,7 @@
import seedu.address.commons.core.Messages;
import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditPersonCommand.EditPersonDescriptor;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
@@ -30,7 +30,7 @@
/**
* Contains integration tests (interaction with the Model) and unit tests for EditCommand.
*/
-public class EditCommandTest {
+public class EditPersonCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
@@ -38,9 +38,9 @@ public class EditCommandTest {
public void execute_allFieldsSpecifiedUnfilteredList_success() {
Person editedPerson = new PersonBuilder().build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
+ EditPersonCommand editCommand = new EditPersonCommand(INDEX_FIRST_PERSON, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditPersonCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
@@ -48,6 +48,7 @@ public void execute_allFieldsSpecifiedUnfilteredList_success() {
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
+
@Test
public void execute_someFieldsSpecifiedUnfilteredList_success() {
Index indexLastPerson = Index.fromOneBased(model.getFilteredPersonList().size());
@@ -55,13 +56,13 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
PersonBuilder personInList = new PersonBuilder(lastPerson);
Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
+ .withJob(VALID_JOB_BOB).build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
- EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
+ .withPhone(VALID_PHONE_BOB).withJob(VALID_JOB_BOB).build();
+ EditPersonCommand editCommand = new EditPersonCommand(indexLastPerson, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditPersonCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(lastPerson, editedPerson);
@@ -71,10 +72,10 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
@Test
public void execute_noFieldSpecifiedUnfilteredList_success() {
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
+ EditPersonCommand editCommand = new EditPersonCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditPersonCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
@@ -87,10 +88,10 @@ public void execute_filteredList_success() {
Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
+ EditPersonCommand editCommand = new EditPersonCommand(INDEX_FIRST_PERSON,
new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
+ String expectedMessage = String.format(EditPersonCommand.MESSAGE_EDIT_PERSON_SUCCESS, editedPerson);
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
@@ -102,34 +103,34 @@ public void execute_filteredList_success() {
public void execute_duplicatePersonUnfilteredList_failure() {
Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ EditPersonCommand editCommand = new EditPersonCommand(INDEX_SECOND_PERSON, descriptor);
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditPersonCommand.MESSAGE_DUPLICATE_PERSON);
}
@Test
public void execute_duplicatePersonFilteredList_failure() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
- // edit person in filtered list into a duplicate in address book
+ // edit applicant in filtered applicant list into a duplicate in address book
Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
+ EditPersonCommand editCommand = new EditPersonCommand(INDEX_FIRST_PERSON,
new EditPersonDescriptorBuilder(personInList).build());
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditPersonCommand.MESSAGE_DUPLICATE_PERSON);
}
@Test
public void execute_invalidPersonIndexUnfilteredList_failure() {
Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor);
+ EditPersonCommand editCommand = new EditPersonCommand(outOfBoundIndex, descriptor);
assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
/**
- * Edit filtered list where index is larger than size of filtered list,
+ * Edit filtered applicant list where index is larger than size of filtered applicant list,
* but smaller than size of address book
*/
@Test
@@ -139,7 +140,7 @@ public void execute_invalidPersonIndexFilteredList_failure() {
// ensures that outOfBoundIndex is still in bounds of address book list
assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
- EditCommand editCommand = new EditCommand(outOfBoundIndex,
+ EditPersonCommand editCommand = new EditPersonCommand(outOfBoundIndex,
new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
@@ -147,11 +148,11 @@ public void execute_invalidPersonIndexFilteredList_failure() {
@Test
public void equals() {
- final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PERSON, DESC_AMY);
+ final EditPersonCommand standardCommand = new EditPersonCommand(INDEX_FIRST_PERSON, DESC_AMY);
// same values -> returns true
EditPersonDescriptor copyDescriptor = new EditPersonDescriptor(DESC_AMY);
- EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PERSON, copyDescriptor);
+ EditPersonCommand commandWithSameValues = new EditPersonCommand(INDEX_FIRST_PERSON, copyDescriptor);
assertTrue(standardCommand.equals(commandWithSameValues));
// same object -> returns true
@@ -161,13 +162,13 @@ public void equals() {
assertFalse(standardCommand.equals(null));
// different types -> returns false
- assertFalse(standardCommand.equals(new ClearCommand()));
+ assertFalse(standardCommand.equals(new HelpCommand()));
// different index -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PERSON, DESC_AMY)));
+ assertFalse(standardCommand.equals(new EditPersonCommand(INDEX_SECOND_PERSON, DESC_AMY)));
// different descriptor -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PERSON, DESC_BOB)));
+ assertFalse(standardCommand.equals(new EditPersonCommand(INDEX_FIRST_PERSON, DESC_BOB)));
}
}
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
index e0288792e72..94e485dfa5b 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
@@ -6,13 +6,14 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
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_JOB_BOB;
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_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_STAGE_BOB;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditPersonCommand.EditPersonDescriptor;
import seedu.address.testutil.EditPersonDescriptorBuilder;
public class EditPersonDescriptorTest {
@@ -51,8 +52,12 @@ public void equals() {
editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
- // different tags -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build();
+ // different job -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withJob(VALID_JOB_BOB).build();
+ assertFalse(DESC_AMY.equals(editedAmy));
+
+ // different stage -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withStage(VALID_STAGE_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
index 9533c473875..e5a0d2425d7 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, null, false, true);
assertCommandSuccess(new ExitCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index 9b15db28bbb..2070f8ecb10 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -1,8 +1,7 @@
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 org.junit.jupiter.api.Assertions.assertNotEquals;
import static seedu.address.commons.core.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.testutil.TypicalPersons.CARL;
@@ -10,15 +9,18 @@
import static seedu.address.testutil.TypicalPersons.FIONA;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
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.NameContainsKeywordsPredicate;
+import seedu.address.model.interview.InterviewContainsKeywordsPredicate;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -29,36 +31,49 @@ public class FindCommandTest {
@Test
public void equals() {
- NameContainsKeywordsPredicate firstPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("first"));
- NameContainsKeywordsPredicate secondPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("second"));
- FindCommand findFirstCommand = new FindCommand(firstPredicate);
- FindCommand findSecondCommand = new FindCommand(secondPredicate);
+ List first = new ArrayList<>();
+ first.add("n/first");
+
+ List second = new ArrayList<>();
+ second.add("n/second");
+
+ PersonContainsKeywordsPredicate firstPredicate = new PersonContainsKeywordsPredicate(first);
+ InterviewContainsKeywordsPredicate secondPredicate = new InterviewContainsKeywordsPredicate(second);
+
+ FindPersonCommand findFirstCommand = new FindPersonCommand(firstPredicate);
+ FindInterviewCommand findSecondCommand = new FindInterviewCommand(secondPredicate);
// same object -> returns true
- assertTrue(findFirstCommand.equals(findFirstCommand));
+ assertEquals(findFirstCommand, findFirstCommand);
// same values -> returns true
- FindCommand findFirstCommandCopy = new FindCommand(firstPredicate);
- assertTrue(findFirstCommand.equals(findFirstCommandCopy));
+ FindPersonCommand findFirstCommandCopy = new FindPersonCommand(firstPredicate);
+ assertEquals(findFirstCommand, findFirstCommandCopy);
+
+ FindInterviewCommand findSecondCommandCopy = new FindInterviewCommand(secondPredicate);
+ assertEquals(findSecondCommand, findSecondCommandCopy);
// different types -> returns false
- assertFalse(findFirstCommand.equals(1));
+ assertNotEquals(1, findFirstCommand);
+ assertNotEquals(1, findSecondCommand);
// null -> returns false
- assertFalse(findFirstCommand.equals(null));
+ assertNotEquals(null, findFirstCommand);
+ assertNotEquals(null, findSecondCommand);
- // different person -> returns false
- assertFalse(findFirstCommand.equals(findSecondCommand));
+ // different applicant -> returns false
+ assertNotEquals(findFirstCommand, findSecondCommand);
}
@Test
public void execute_zeroKeywords_noPersonFound() {
+ List